11package org .prebid .server .analytics .reporter .liveintent ;
22
33import com .fasterxml .jackson .databind .ObjectMapper ;
4+ import com .iab .openrtb .request .BidRequest ;
5+ import com .iab .openrtb .request .Imp ;
6+ import com .iab .openrtb .response .Bid ;
7+ import com .iab .openrtb .response .BidResponse ;
8+ import com .iab .openrtb .response .SeatBid ;
49import io .vertx .core .Future ;
5- import io .vertx .core .MultiMap ;
610import org .junit .jupiter .api .BeforeEach ;
711import org .junit .jupiter .api .extension .ExtendWith ;
812import org .mockito .ArgumentCaptor ;
1115import org .junit .jupiter .api .Test ;
1216import org .mockito .junit .jupiter .MockitoExtension ;
1317import org .prebid .server .VertxTest ;
18+ import org .prebid .server .analytics .model .AuctionEvent ;
1419import org .prebid .server .analytics .model .NotificationEvent ;
1520import org .prebid .server .analytics .reporter .liveintent .model .LiveIntentAnalyticsProperties ;
21+ import org .prebid .server .analytics .reporter .liveintent .model .PbsjBid ;
22+ import org .prebid .server .auction .model .AuctionContext ;
23+ import org .prebid .server .hooks .execution .model .ExecutionStatus ;
24+ import org .prebid .server .hooks .execution .model .GroupExecutionOutcome ;
25+ import org .prebid .server .hooks .execution .model .HookExecutionContext ;
26+ import org .prebid .server .hooks .execution .model .HookExecutionOutcome ;
27+ import org .prebid .server .hooks .execution .model .HookId ;
28+ import org .prebid .server .hooks .execution .model .Stage ;
29+ import org .prebid .server .hooks .execution .model .StageExecutionOutcome ;
30+ import org .prebid .server .hooks .execution .v1 .analytics .ActivityImpl ;
31+ import org .prebid .server .hooks .execution .v1 .analytics .TagsImpl ;
1632import org .prebid .server .json .JacksonMapper ;
33+ import org .prebid .server .model .Endpoint ;
34+ import org .prebid .server .util .ListUtil ;
1735import org .prebid .server .vertx .httpclient .HttpClient ;
1836import org .prebid .server .vertx .httpclient .model .HttpClientResponse ;
1937
38+ import java .math .BigDecimal ;
39+ import java .util .Arrays ;
40+ import java .util .EnumMap ;
41+ import java .util .List ;
42+
43+ import static org .assertj .core .api .Assertions .assertThat ;
2044import static org .mockito .ArgumentMatchers .anyLong ;
2145import static org .mockito .ArgumentMatchers .anyString ;
2246import static org .mockito .ArgumentMatchers .eq ;
2751@ ExtendWith (MockitoExtension .class )
2852public class LiveintentAnalyticsReporterTest extends VertxTest {
2953
30- private static final HttpClientResponse SUCCESS_RESPONSE = HttpClientResponse .of (
31- 200 , MultiMap .caseInsensitiveMultiMap (), "OK" );
32-
3354 @ Mock
3455 private HttpClient httpClient ;
3556
57+ @ Captor
58+ private ArgumentCaptor <String > jsonCaptor ;
59+
3660 private LiveIntentAnalyticsReporter target ;
3761
3862 private LiveIntentAnalyticsProperties properties ;
@@ -58,15 +82,180 @@ public void setUp() {
5882
5983 @ Test
6084 public void shouldProcessNotificationEvent () {
85+ // given
86+ final HttpClientResponse mockResponse = mock (HttpClientResponse .class );
87+ when (httpClient .get (anyString (), anyLong ())).thenReturn (Future .succeededFuture (mockResponse ));
6188
6289 // when
6390 target .processEvent (NotificationEvent .builder ().bidId ("123" ).bidder ("foo" ).build ());
64- final HttpClientResponse mockResponse = mock (HttpClientResponse .class );
6591
66- when (httpClient .get (anyString (), anyLong ())).thenReturn (Future .succeededFuture (mockResponse ));
6792 // then
6893 // Verify that the HTTP client was called with the expected parameters
69- verify (httpClient ).get (eq (properties .getAnalyticsEndpoint () + "/analytic-events/pbsj-winning-bid" )
70- + "?b=foo&bidId=123" , eq (properties .getTimeoutMs ()));
94+ verify (httpClient ).get (eq (properties .getAnalyticsEndpoint () + "/analytic-events/pbsj-winning-bid"
95+ + "?b=foo&bidId=123" ), eq (properties .getTimeoutMs ()));
96+ }
97+
98+ @ Test
99+ public void shouldSendAllBidsToLiveIntent () {
100+ // given
101+ final HttpClientResponse mockResponse = mock (HttpClientResponse .class );
102+ when (httpClient .post (anyString (), anyString (), anyLong ()))
103+ .thenReturn (Future .succeededFuture (mockResponse ));
104+
105+ // when
106+ target .processEvent (buildEvent (true ));
107+
108+ // then
109+ verify (httpClient ).post (
110+ eq (properties .getAnalyticsEndpoint () + "/analytic-events/pbsj-bids" ),
111+ jsonCaptor .capture (),
112+ eq (properties .getTimeoutMs ()));
113+
114+ final String capturedJson = jsonCaptor .getValue ();
115+ final List <PbsjBid > pbsjBids = Arrays .stream (jacksonMapper .decodeValue (capturedJson , PbsjBid [].class )).toList ();
116+ assertThat (pbsjBids ).isEqualTo (List .of (
117+ PbsjBid .builder ()
118+ .bidId ("bid-id" )
119+ .price (BigDecimal .ONE )
120+ .adUnitId ("ad-unit-id" )
121+ .enriched (true )
122+ .currency ("USD" )
123+ .treatmentRate (0.5f )
124+ .timestamp (0L )
125+ .partnerId ("pbsj" )
126+ .build ()
127+ ));
128+ }
129+
130+ @ Test
131+ public void shouldSendAllBidsToLiveIntentNotEnriched () {
132+ // given
133+ final HttpClientResponse mockResponse = mock (HttpClientResponse .class );
134+ when (httpClient .post (anyString (), anyString (), anyLong ()))
135+ .thenReturn (Future .succeededFuture (mockResponse ));
136+
137+ // when
138+ target .processEvent (buildEvent (false ));
139+
140+ // then
141+ verify (httpClient ).post (
142+ eq (properties .getAnalyticsEndpoint () + "/analytic-events/pbsj-bids" ),
143+ jsonCaptor .capture (),
144+ eq (properties .getTimeoutMs ()));
145+
146+ final String capturedJson = jsonCaptor .getValue ();
147+ final List <PbsjBid > pbsjBids = Arrays .stream (jacksonMapper .decodeValue (capturedJson , PbsjBid [].class )).toList ();
148+ assertThat (pbsjBids ).isEqualTo (List .of (
149+ PbsjBid .builder ()
150+ .bidId ("bid-id" )
151+ .price (BigDecimal .ONE )
152+ .adUnitId ("ad-unit-id" )
153+ .enriched (false )
154+ .currency ("USD" )
155+ .treatmentRate (0.5f )
156+ .timestamp (0L )
157+ .partnerId ("pbsj" )
158+ .build ()
159+ ));
160+ }
161+
162+ @ Test
163+ public void shouldSendAllBidsToLiveIntentNoTreatmentRate () {
164+ // given
165+ final HttpClientResponse mockResponse = mock (HttpClientResponse .class );
166+ when (httpClient .post (anyString (), anyString (), anyLong ()))
167+ .thenReturn (Future .succeededFuture (mockResponse ));
168+
169+ // when
170+ target .processEvent (buildEvent (false , false ));
171+
172+ // then
173+ verify (httpClient ).post (
174+ eq (properties .getAnalyticsEndpoint () + "/analytic-events/pbsj-bids" ),
175+ jsonCaptor .capture (),
176+ eq (properties .getTimeoutMs ()));
177+
178+ final String capturedJson = jsonCaptor .getValue ();
179+ final List <PbsjBid > pbsjBids = Arrays .stream (jacksonMapper .decodeValue (capturedJson , PbsjBid [].class )).toList ();
180+ assertThat (pbsjBids ).isEqualTo (List .of (
181+ PbsjBid .builder ()
182+ .bidId ("bid-id" )
183+ .price (BigDecimal .ONE )
184+ .adUnitId ("ad-unit-id" )
185+ .enriched (false )
186+ .currency ("USD" )
187+ .treatmentRate (-1.0f )
188+ .timestamp (0L )
189+ .partnerId ("pbsj" )
190+ .build ()
191+ ));
192+ }
193+
194+ private AuctionEvent buildEvent (Boolean isEnriched ) {
195+ return buildEvent (isEnriched , true );
196+ }
197+
198+ private AuctionEvent buildEvent (Boolean isEnriched , Boolean withTags ) {
199+ final HookId hookId = HookId .of (
200+ "liveintent-omni-channel-identity-enrichment-hook" ,
201+ "liveintent-omni-channel-identity-enrichment-hook" );
202+
203+ final ActivityImpl enrichmentRate = ActivityImpl .of ("liveintent-treatment-rate" , "0.5" , List .of ());
204+
205+ final List <ActivityImpl > enriched = isEnriched
206+ ? List .of (ActivityImpl .of ("liveintent-enriched" , "success" , List .of ()))
207+ : List .of ();
208+
209+ final HookExecutionOutcome hookExecutionOutcome = HookExecutionOutcome .builder ()
210+ .hookId (hookId )
211+ .executionTime (100L )
212+ .status (ExecutionStatus .success )
213+ .analyticsTags (TagsImpl .of (
214+ withTags
215+ ? ListUtil .union (
216+ List .of (enrichmentRate ),
217+ enriched
218+ )
219+ : List .of ()
220+ ))
221+ .action (null )
222+ .build ();
223+
224+ final StageExecutionOutcome stageExecutionOutcome = StageExecutionOutcome .of (
225+ "auction-request" ,
226+ List .of (GroupExecutionOutcome .of (List .of (hookExecutionOutcome )))
227+ );
228+
229+ final EnumMap <Stage , List <StageExecutionOutcome >> stageOutcomes = new EnumMap <>(Stage .class );
230+ stageOutcomes .put (Stage .processed_auction_request , List .of (stageExecutionOutcome ));
231+ return AuctionEvent .builder ()
232+ .auctionContext (
233+ AuctionContext .builder ()
234+ .bidRequest (BidRequest .builder ()
235+ .id ("request-id" )
236+ .imp (List .of (
237+ Imp .builder ()
238+ .id ("imp-id" )
239+ .tagid ("ad-unit-id" )
240+ .build ()))
241+ .build ())
242+ .bidResponse (BidResponse .builder ()
243+ .bidid ("bid-id" )
244+ .cur ("USD" )
245+ .seatbid (List .of (
246+ SeatBid .builder ()
247+ .bid (List .of (
248+ Bid .builder ()
249+ .id ("bid-id" )
250+ .impid ("imp-id" )
251+ .price (BigDecimal .ONE )
252+ .build ()))
253+ .build ()))
254+ .build ())
255+ .hookExecutionContext (HookExecutionContext .of (
256+ Endpoint .openrtb2_auction ,
257+ stageOutcomes ))
258+ .build ())
259+ .build ();
71260 }
72261}
0 commit comments