@@ -4,13 +4,23 @@ use chrono::{TimeZone, Utc};
4
4
use once_cell:: sync:: Lazy ;
5
5
6
6
use crate :: {
7
+ balances:: { Balances , UncheckedState } ,
7
8
campaign:: { Active , Pricing , Validators } ,
8
9
channel:: Nonce ,
9
10
config:: GANACHE_CONFIG ,
10
- sentry:: { CLICK , IMPRESSION } ,
11
+ sentry:: {
12
+ message:: Message , LastApproved , LastApprovedResponse , MessageResponse , SuccessResponse ,
13
+ ValidatorMessage , ValidatorMessagesListResponse , CLICK , IMPRESSION ,
14
+ } ,
11
15
targeting:: Rules ,
12
- AdUnit , Address , Campaign , Channel , EventSubmission , UnifiedNum , ValidatorDesc , ValidatorId ,
13
- IPFS ,
16
+ validator:: { ApproveState , Heartbeat , MessageTypes , NewState , RejectState } ,
17
+ AdUnit , Address , Campaign , Channel , EventSubmission , ToETHChecksum , UnifiedNum , ValidatorDesc ,
18
+ ValidatorId , IPFS ,
19
+ } ;
20
+
21
+ use wiremock:: {
22
+ matchers:: { method, path, query_param} ,
23
+ Mock , MockGuard , MockServer , ResponseTemplate ,
14
24
} ;
15
25
16
26
pub use logger:: discard_logger;
@@ -296,6 +306,190 @@ pub static DUMMY_IPFS: Lazy<[IPFS; 5]> = Lazy::new(|| {
296
306
]
297
307
} ) ;
298
308
309
+ pub struct ServerSetup {
310
+ pub server : MockServer ,
311
+ }
312
+
313
+ impl ServerSetup {
314
+ pub async fn init ( channel : & Channel ) -> Self {
315
+ let server = MockServer :: start ( ) . await ;
316
+ let ok_response = SuccessResponse { success : true } ;
317
+
318
+ // Making sure all propagations to leader/follower succeed
319
+ Mock :: given ( method ( "POST" ) )
320
+ . and ( path ( format ! (
321
+ "leader/v5/channel/{}/validator-messages" ,
322
+ channel. id( )
323
+ ) ) )
324
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & ok_response) )
325
+ . mount ( & server)
326
+ . await ;
327
+
328
+ Mock :: given ( method ( "POST" ) )
329
+ . and ( path ( format ! (
330
+ "follower/v5/channel/{}/validator-messages" ,
331
+ channel. id( )
332
+ ) ) )
333
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & ok_response) )
334
+ . mount ( & server)
335
+ . await ;
336
+
337
+ let heartbeat = Heartbeat {
338
+ signature : String :: new ( ) ,
339
+ state_root : String :: new ( ) ,
340
+ timestamp : Utc :: now ( ) ,
341
+ } ;
342
+ let heartbeat_res = ValidatorMessagesListResponse {
343
+ messages : vec ! [ ValidatorMessage {
344
+ from: DUMMY_CAMPAIGN . channel. leader,
345
+ received: Utc :: now( ) ,
346
+ msg: MessageTypes :: Heartbeat ( heartbeat) ,
347
+ } ] ,
348
+ } ;
349
+ Mock :: given ( method ( "GET" ) )
350
+ . and ( path ( format ! (
351
+ "/v5/channel/{}/validator-messages/{}/{}" ,
352
+ DUMMY_CAMPAIGN . channel. id( ) ,
353
+ DUMMY_CAMPAIGN . channel. leader,
354
+ "Heartbeat" ,
355
+ ) ) )
356
+ . and ( query_param ( "limit" , "1" ) )
357
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & heartbeat_res) )
358
+ . mount ( & server)
359
+ . await ;
360
+
361
+ Self { server }
362
+ }
363
+
364
+ pub async fn setup_new_state_response (
365
+ & self ,
366
+ new_state_msg : Option < NewState < UncheckedState > > ,
367
+ ) -> MockGuard {
368
+ let new_state_res = match new_state_msg {
369
+ Some ( msg) => ValidatorMessagesListResponse {
370
+ messages : vec ! [ ValidatorMessage {
371
+ from: DUMMY_CAMPAIGN . channel. leader,
372
+ received: Utc :: now( ) ,
373
+ msg: MessageTypes :: NewState ( msg) ,
374
+ } ] ,
375
+ } ,
376
+ None => ValidatorMessagesListResponse { messages : vec ! [ ] } ,
377
+ } ;
378
+
379
+ Mock :: given ( method ( "GET" ) )
380
+ . and ( path ( format ! (
381
+ "/v5/channel/{}/validator-messages/{}/{}" ,
382
+ DUMMY_CAMPAIGN . channel. id( ) ,
383
+ DUMMY_CAMPAIGN . channel. leader,
384
+ "NewState" ,
385
+ ) ) )
386
+ . and ( query_param ( "limit" , "1" ) )
387
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & new_state_res) )
388
+ . expect ( 1 )
389
+ . named ( "GET NewState helper" )
390
+ . mount_as_scoped ( & self . server )
391
+ . await
392
+ }
393
+
394
+ // Gets wiremock to return a specific ApproveState message or None when called
395
+ pub async fn setup_approve_state_response (
396
+ & self ,
397
+ approve_state : Option < ApproveState > ,
398
+ ) -> MockGuard {
399
+ let approve_state_res = match approve_state {
400
+ Some ( msg) => ValidatorMessagesListResponse {
401
+ messages : vec ! [ ValidatorMessage {
402
+ from: DUMMY_CAMPAIGN . channel. follower,
403
+ received: Utc :: now( ) ,
404
+ msg: MessageTypes :: ApproveState ( msg) ,
405
+ } ] ,
406
+ } ,
407
+ None => ValidatorMessagesListResponse { messages : vec ! [ ] } ,
408
+ } ;
409
+
410
+ Mock :: given ( method ( "GET" ) )
411
+ . and ( path ( format ! (
412
+ "/v5/channel/{}/validator-messages/{}/{}" ,
413
+ DUMMY_CAMPAIGN . channel. id( ) ,
414
+ DUMMY_CAMPAIGN . channel. leader,
415
+ "ApproveState+RejectState" ,
416
+ ) ) )
417
+ . and ( query_param ( "limit" , "1" ) )
418
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & approve_state_res) )
419
+ . expect ( 1 )
420
+ . named ( "GET ApproveState helper" )
421
+ . mount_as_scoped ( & self . server )
422
+ . await
423
+ }
424
+
425
+ // Gets wiremock to return a specific RejectState message or None when called
426
+ pub async fn setup_reject_state_response (
427
+ & self ,
428
+ reject_state : Option < RejectState < UncheckedState > > ,
429
+ ) -> MockGuard {
430
+ let reject_state_res = match reject_state {
431
+ Some ( msg) => ValidatorMessagesListResponse {
432
+ messages : vec ! [ ValidatorMessage {
433
+ from: DUMMY_CAMPAIGN . channel. follower,
434
+ received: Utc :: now( ) ,
435
+ msg: MessageTypes :: RejectState ( msg) ,
436
+ } ] ,
437
+ } ,
438
+ None => ValidatorMessagesListResponse { messages : vec ! [ ] } ,
439
+ } ;
440
+
441
+ Mock :: given ( method ( "GET" ) )
442
+ . and ( path ( format ! (
443
+ "/v5/channel/{}/validator-messages/{}/{}" ,
444
+ DUMMY_CAMPAIGN . channel. id( ) ,
445
+ DUMMY_CAMPAIGN . channel. leader,
446
+ "ApproveState+RejectState" ,
447
+ ) ) )
448
+ . and ( query_param ( "limit" , "1" ) )
449
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & reject_state_res) )
450
+ . expect ( 1 )
451
+ . named ( "GET RejectState helper" )
452
+ . mount_as_scoped ( & self . server )
453
+ . await
454
+ }
455
+
456
+ pub async fn setup_last_approved_response (
457
+ & self ,
458
+ balances : Balances < UncheckedState > ,
459
+ state_root : String ,
460
+ ) -> MockGuard {
461
+ let last_approved_new_state: NewState < UncheckedState > = NewState {
462
+ state_root,
463
+ signature : IDS [ & * LEADER ] . to_checksum ( ) ,
464
+ balances : balances. into_unchecked ( ) ,
465
+ } ;
466
+ let new_state_res = MessageResponse {
467
+ from : IDS [ & * LEADER ] ,
468
+ received : Utc :: now ( ) ,
469
+ msg : Message :: new ( last_approved_new_state) ,
470
+ } ;
471
+ let last_approved_response = LastApprovedResponse {
472
+ last_approved : Some ( LastApproved {
473
+ new_state : Some ( new_state_res) ,
474
+ approve_state : None ,
475
+ } ) ,
476
+ heartbeats : None ,
477
+ } ;
478
+
479
+ Mock :: given ( method ( "GET" ) )
480
+ . and ( path ( format ! (
481
+ "/v5/channel/{}/last-approved" ,
482
+ DUMMY_CAMPAIGN . channel. id( ) ,
483
+ ) ) )
484
+ . and ( query_param ( "withHeartbeat" , "true" ) )
485
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & last_approved_response) )
486
+ . expect ( 1 )
487
+ . named ( "GET LastApproved helper" )
488
+ . mount_as_scoped ( & self . server )
489
+ . await
490
+ }
491
+ }
492
+
299
493
#[ cfg( test) ]
300
494
mod test {
301
495
use super :: * ;
0 commit comments