@@ -250,7 +250,7 @@ impl Manager {
250250
251251 // Test with different units with price
252252 // 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 > {
254254 let deposit_asset = self
255255 . options
256256 . whitelisted_tokens
@@ -268,14 +268,18 @@ impl Manager {
268268 . ok_or ( Error :: NoValidators ) ?;
269269
270270 let url = format ! (
271- "{}/units-for-slot/{}?{}" ,
271+ "{}/v5/ units-for-slot/{}?{}" ,
272272 first_validator. url, self . options. market_slot, deposit_asset
273273 ) ;
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" ) ;
275279
276280 for validator in self . options . validators . iter ( ) . skip ( 1 ) {
277281 let url = format ! (
278- "{}/units-for-slot/{}?{}" ,
282+ "{}/v5/ units-for-slot/{}?{}" ,
279283 validator. url, self . options. market_slot, deposit_asset
280284 ) ;
281285 let new_res: Response = self . client . get ( url) . send ( ) . await ?. json ( ) . await ?;
@@ -290,7 +294,7 @@ impl Manager {
290294 }
291295
292296 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 ?;
294298 let m_campaigns = & units_for_slot. campaigns ;
295299 let fallback_unit = units_for_slot. fallback_unit ;
296300 let targeting_input = units_for_slot. targeting_input_base ;
@@ -435,3 +439,193 @@ impl Manager {
435439 }
436440 }
437441}
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