@@ -250,7 +250,7 @@ impl Manager {
250
250
251
251
// Test with different units with price
252
252
// Test if first campaign is not overwritten
253
- pub async fn get_market_demand_resp ( & self ) -> Result < Response , Error > {
253
+ pub async fn get_units_for_slot_resp ( & self ) -> Result < Response , Error > {
254
254
let deposit_asset = self
255
255
. options
256
256
. whitelisted_tokens
@@ -268,14 +268,18 @@ impl Manager {
268
268
. ok_or ( Error :: NoValidators ) ?;
269
269
270
270
let url = format ! (
271
- "{}/units-for-slot/{}?{}" ,
271
+ "{}/v5/ units-for-slot/{}?{}" ,
272
272
first_validator. url, self . options. market_slot, deposit_asset
273
273
) ;
274
- let mut first_res: Response = self . client . get ( url) . send ( ) . await ?. json ( ) . await ?;
274
+
275
+ // Ordering of the campaigns matters so we will just push them to the first result
276
+ // We reuse `targeting_input_base`, `accepted_referrers` and `fallback_unit`
277
+ let json_res: String = self . client . get ( url) . send ( ) . await ?. text ( ) . await ?;
278
+ let mut first_res: Response = serde_json:: from_str ( & json_res) . expect ( "Should convert" ) ;
275
279
276
280
for validator in self . options . validators . iter ( ) . skip ( 1 ) {
277
281
let url = format ! (
278
- "{}/units-for-slot/{}?{}" ,
282
+ "{}/v5/ units-for-slot/{}?{}" ,
279
283
validator. url, self . options. market_slot, deposit_asset
280
284
) ;
281
285
let new_res: Response = self . client . get ( url) . send ( ) . await ?. json ( ) . await ?;
@@ -290,7 +294,7 @@ impl Manager {
290
294
}
291
295
292
296
pub async fn get_next_ad_unit ( & self ) -> Result < Option < NextAdUnit > , Error > {
293
- let units_for_slot = self . get_market_demand_resp ( ) . await ?;
297
+ let units_for_slot = self . get_units_for_slot_resp ( ) . await ?;
294
298
let m_campaigns = & units_for_slot. campaigns ;
295
299
let fallback_unit = units_for_slot. fallback_unit ;
296
300
let targeting_input = units_for_slot. targeting_input_base ;
@@ -435,3 +439,193 @@ impl Manager {
435
439
}
436
440
}
437
441
}
442
+
443
+ #[ cfg( test) ]
444
+ mod test {
445
+ use super :: * ;
446
+ use crate :: manager:: input:: Input ;
447
+ use adex_primitives:: {
448
+ sentry:: CLICK ,
449
+ test_util:: {
450
+ CAMPAIGNS , DUMMY_AD_UNITS , DUMMY_IPFS , DUMMY_VALIDATOR_FOLLOWER ,
451
+ DUMMY_VALIDATOR_LEADER , IDS , LEADER_2 , PUBLISHER ,
452
+ } ,
453
+ } ;
454
+ use wiremock:: {
455
+ matchers:: { method, path} ,
456
+ Mock , MockServer , ResponseTemplate ,
457
+ } ;
458
+
459
+ #[ tokio:: test]
460
+ async fn test_querying_for_units_for_slot ( ) {
461
+ // 1. Set up mock servers for each validator
462
+ let server = MockServer :: start ( ) . await ;
463
+ let slot = DUMMY_IPFS [ 0 ] ;
464
+ let seconds_since_epoch = Utc :: now ( ) ;
465
+
466
+ let original_input = Input {
467
+ ad_view : None ,
468
+ global : input:: Global {
469
+ ad_slot_id : DUMMY_IPFS [ 0 ] ,
470
+ ad_slot_type : "legacy_250x250" . to_string ( ) ,
471
+ publisher_id : * PUBLISHER ,
472
+ country : None ,
473
+ event_type : IMPRESSION ,
474
+ // we can't know only the timestamp
475
+ seconds_since_epoch,
476
+ user_agent_os : Some ( "Linux" . to_string ( ) ) ,
477
+ user_agent_browser_family : Some ( "Firefox" . to_string ( ) ) ,
478
+ } ,
479
+ // no AdUnit should be present
480
+ ad_unit_id : None ,
481
+ // no balances
482
+ balances : None ,
483
+ // no campaign
484
+ campaign : None ,
485
+ ad_slot : Some ( input:: AdSlot {
486
+ categories : vec ! [ "IAB3" . into( ) , "IAB13-7" . into( ) , "IAB5" . into( ) ] ,
487
+ hostname : "adex.network" . to_string ( ) ,
488
+ } ) ,
489
+ } ;
490
+
491
+ let modified_input = Input {
492
+ ad_view : None ,
493
+ global : input:: Global {
494
+ ad_slot_id : DUMMY_IPFS [ 1 ] ,
495
+ ad_slot_type : "legacy_250x250" . to_string ( ) ,
496
+ publisher_id : * PUBLISHER ,
497
+ country : None ,
498
+ event_type : CLICK ,
499
+ // we can't know only the timestamp
500
+ seconds_since_epoch,
501
+ user_agent_os : Some ( "Linux" . to_string ( ) ) ,
502
+ user_agent_browser_family : Some ( "Firefox" . to_string ( ) ) ,
503
+ } ,
504
+ // no AdUnit should be present
505
+ ad_unit_id : None ,
506
+ // no balances
507
+ balances : None ,
508
+ // no campaign
509
+ campaign : None ,
510
+ ad_slot : Some ( input:: AdSlot {
511
+ categories : vec ! [ "IAB3" . into( ) , "IAB13-7" . into( ) , "IAB5" . into( ) ] ,
512
+ hostname : "adex.network" . to_string ( ) ,
513
+ } ) ,
514
+ } ;
515
+
516
+ let original_referrers = vec ! [ Url :: parse( "https://ambire.com" ) . expect( "should parse" ) ] ;
517
+ let modified_referrers =
518
+ vec ! [ Url :: parse( "https://www.google.com/adsense/start/" ) . expect( "should parse" ) ] ;
519
+
520
+ let unit_0 = DUMMY_AD_UNITS [ 0 ] . clone ( ) ;
521
+ let original_ad_unit = AdUnit {
522
+ ipfs : unit_0. ipfs ,
523
+ media_url : unit_0. media_url ,
524
+ media_mime : unit_0. media_mime ,
525
+ target_url : unit_0. target_url ,
526
+ } ;
527
+
528
+ let unit_1 = DUMMY_AD_UNITS [ 1 ] . clone ( ) ;
529
+ let modified_ad_unit = AdUnit {
530
+ ipfs : unit_1. ipfs ,
531
+ media_url : unit_1. media_url ,
532
+ media_mime : unit_1. media_mime ,
533
+ target_url : unit_1. target_url ,
534
+ } ;
535
+
536
+ let campaign_0 = Campaign {
537
+ campaign : CAMPAIGNS [ 0 ] . clone ( ) . context ,
538
+ units_with_price : Vec :: new ( ) ,
539
+ } ;
540
+
541
+ let campaign_1 = Campaign {
542
+ campaign : CAMPAIGNS [ 1 ] . clone ( ) . context ,
543
+ units_with_price : Vec :: new ( ) ,
544
+ } ;
545
+
546
+ let campaign_2 = Campaign {
547
+ campaign : CAMPAIGNS [ 2 ] . clone ( ) . context ,
548
+ units_with_price : Vec :: new ( ) ,
549
+ } ;
550
+
551
+ // Original response
552
+ let response_1 = Response {
553
+ targeting_input_base : original_input. clone ( ) ,
554
+ accepted_referrers : original_referrers. clone ( ) ,
555
+ fallback_unit : Some ( original_ad_unit. clone ( ) ) ,
556
+ campaigns : vec ! [ campaign_0. clone( ) ] ,
557
+ } ;
558
+
559
+ // Different targeting_input_base, fallback_unit, accepted_referrers, 1 new campaign and 1 repeating campaign
560
+ let response_2 = Response {
561
+ targeting_input_base : modified_input. clone ( ) ,
562
+ accepted_referrers : modified_referrers. clone ( ) ,
563
+ fallback_unit : Some ( modified_ad_unit. clone ( ) ) ,
564
+ campaigns : vec ! [ campaign_0. clone( ) , campaign_1. clone( ) ] ,
565
+ } ;
566
+
567
+ // 1 new campaigns, 2 repeating campaigns
568
+ let response_3 = Response {
569
+ targeting_input_base : modified_input,
570
+ accepted_referrers : modified_referrers,
571
+ fallback_unit : Some ( modified_ad_unit) ,
572
+ campaigns : vec ! [ campaign_0. clone( ) , campaign_1. clone( ) , campaign_2. clone( ) ] ,
573
+ } ;
574
+
575
+ Mock :: given ( method ( "GET" ) )
576
+ . and ( path ( format ! ( "1/v5/units-for-slot/{}" , slot, ) ) )
577
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & response_1) )
578
+ . mount ( & server)
579
+ . await ;
580
+
581
+ Mock :: given ( method ( "GET" ) )
582
+ . and ( path ( format ! ( "2/v5/units-for-slot/{}" , slot, ) ) )
583
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & response_2) )
584
+ . mount ( & server)
585
+ . await ;
586
+
587
+ Mock :: given ( method ( "GET" ) )
588
+ . and ( path ( format ! ( "3/v5/units-for-slot/{}" , slot, ) ) )
589
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( & response_3) )
590
+ . mount ( & server)
591
+ . await ;
592
+
593
+ // 2. Set up a manager
594
+ let market_url = server. uri ( ) . parse ( ) . unwrap ( ) ;
595
+ let whitelisted_tokens = DEFAULT_TOKENS . clone ( ) ;
596
+ let publisher_addr = "0x0000000000000000626f62627973686d75726461"
597
+ . parse ( )
598
+ . unwrap ( ) ;
599
+ let mut validator_1 = DUMMY_VALIDATOR_LEADER . clone ( ) ;
600
+ validator_1. url = format ! ( "{}/1" , server. uri( ) ) ;
601
+ let mut validator_2 = DUMMY_VALIDATOR_FOLLOWER . clone ( ) ;
602
+ validator_2. url = format ! ( "{}/2" , server. uri( ) ) ;
603
+ let mut validator_3 = DUMMY_VALIDATOR_LEADER . clone ( ) ;
604
+ validator_3. id = IDS [ & LEADER_2 ] ;
605
+ validator_3. url = format ! ( "{}/3" , server. uri( ) ) ;
606
+ let options = Options {
607
+ market_url,
608
+ market_slot : DUMMY_IPFS [ 0 ] ,
609
+ publisher_addr,
610
+ // All passed tokens must be of the same price and decimals, so that the amounts can be accurately compared
611
+ whitelisted_tokens,
612
+ size : Some ( Size :: new ( 300 , 100 ) ) ,
613
+ navigator_language : Some ( "bg" . into ( ) ) ,
614
+ disabled_video : false ,
615
+ disabled_sticky : false ,
616
+ validators : vec ! [ validator_1, validator_2, validator_3] ,
617
+ } ;
618
+
619
+ let manager = Manager :: new ( options. clone ( ) , Default :: default ( ) )
620
+ . expect ( "Failed to create AdView Manager" ) ;
621
+
622
+ let res = manager
623
+ . get_units_for_slot_resp ( )
624
+ . await
625
+ . expect ( "Should get response" ) ;
626
+ assert_eq ! ( res. targeting_input_base. global. ad_slot_id, DUMMY_IPFS [ 0 ] ) ;
627
+ assert_eq ! ( res. accepted_referrers, original_referrers) ;
628
+ assert_eq ! ( res. fallback_unit, Some ( original_ad_unit) ) ;
629
+ assert_eq ! ( res. campaigns, vec![ campaign_0, campaign_1, campaign_2] ) ;
630
+ }
631
+ }
0 commit comments