1717import org .prebid .server .bidder .model .HttpRequest ;
1818import org .prebid .server .bidder .model .HttpResponse ;
1919import org .prebid .server .bidder .model .Result ;
20+ import org .prebid .server .proto .openrtb .ext .ExtPrebid ;
21+ import org .prebid .server .proto .openrtb .ext .request .smilewanted .ExtImpSmilewanted ;
2022import org .prebid .server .util .HttpUtil ;
2123
24+ import java .math .BigDecimal ;
25+ import java .util .Arrays ;
2226import java .util .List ;
2327import java .util .Map ;
2428import java .util .function .Function ;
2832import static org .assertj .core .api .Assertions .assertThatIllegalArgumentException ;
2933import static org .assertj .core .api .Assertions .tuple ;
3034import static org .prebid .server .proto .openrtb .ext .response .BidType .banner ;
35+ import static org .assertj .core .api .Assertions .assertThatNullPointerException ;
3136import static org .prebid .server .proto .openrtb .ext .response .BidType .video ;
3237
3338public class SmileWantedBidderTest extends VertxTest {
3439
35- private static final String ENDPOINT_URL = "https://{{Host}}/test?param={{PublisherId}} " ;
40+ private static final String ENDPOINT_URL = "https://prebid-server.smilewanted.com/java/ " ;
3641
3742 private final SmileWantedBidder target = new SmileWantedBidder (ENDPOINT_URL , jacksonMapper );
3843
@@ -42,13 +47,93 @@ public void creationShouldFailOnInvalidEndpointUrl() {
4247 }
4348
4449 @ Test
45- public void makeHttpRequestsShouldCorrectlyAddHeaders () {
50+ public void creationShouldFailOnNullEndpointUrl () {
51+ assertThatNullPointerException ().isThrownBy (() -> new SmileWantedBidder (null , jacksonMapper ));
52+ }
53+
54+ @ Test
55+ public void creationShouldFailOnNullMapper () {
56+ assertThatNullPointerException ().isThrownBy (() -> new SmileWantedBidder (ENDPOINT_URL , null ));
57+ }
58+
59+ @ Test
60+ public void makeHttpRequestsShouldReturnErrorIfNoImpressions () {
4661 // given
4762 final BidRequest bidRequest = BidRequest .builder ().build ();
4863
4964 // when
5065 final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
5166
67+ // then
68+ assertThat (result .getValue ()).isEmpty ();
69+ assertThat (result .getErrors ())
70+ .containsExactly (BidderError .badInput ("No impressions in request" ));
71+ }
72+
73+ @ Test
74+ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed () {
75+ // given
76+ final BidRequest bidRequest = BidRequest .builder ()
77+ .imp (singletonList (Imp .builder ()
78+ .id ("123" )
79+ .ext (mapper .valueToTree (ExtPrebid .of (null , mapper .createArrayNode ())))
80+ .build ()))
81+ .build ();
82+
83+ // when
84+ final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
85+
86+ // then
87+ assertThat (result .getValue ()).isEmpty ();
88+ assertThat (result .getErrors ()).hasSize (1 )
89+ .allSatisfy (error -> {
90+ assertThat (error .getType ()).isEqualTo (BidderError .Type .bad_input );
91+ assertThat (error .getMessage ()).startsWith ("Missing bidder ext in impression with id: 123" );
92+ });
93+ }
94+
95+ @ Test
96+ public void makeHttpRequestsShouldReturnSingleRequest () {
97+ // given
98+ final BidRequest bidRequest = BidRequest .builder ()
99+ .imp (singletonList (givenImp ("zone123" )))
100+ .build ();
101+
102+ // when
103+ final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
104+
105+ // then
106+ assertThat (result .getErrors ()).isEmpty ();
107+ assertThat (result .getValue ()).hasSize (1 );
108+ }
109+
110+ @ Test
111+ public void makeHttpRequestsShouldBuildCorrectEndpointUrlWithZoneId () {
112+ // given
113+ final BidRequest bidRequest = BidRequest .builder ()
114+ .imp (singletonList (givenImp ("zone456" )))
115+ .build ();
116+
117+ // when
118+ final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
119+
120+ // then
121+ assertThat (result .getErrors ()).isEmpty ();
122+ assertThat (result .getValue ())
123+ .extracting (HttpRequest ::getUri )
124+ .containsExactly ("https://prebid-server.smilewanted.com/java/zone456" );
125+ }
126+
127+ @ Test
128+ public void makeHttpRequestsShouldCorrectlyAddHeaders () {
129+ // given
130+ final BidRequest bidRequest = BidRequest .builder ()
131+ .imp (singletonList (givenImp ("zone123" )))
132+ .build ();
133+
134+ // when
135+ final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
136+
52137 // then
53138 assertThat (result .getErrors ()).isEmpty ();
54139 assertThat (result .getValue ())
@@ -65,7 +150,9 @@ public void makeHttpRequestsShouldCorrectlyAddHeaders() {
65150 @ Test
66151 public void makeHttpRequestsShouldSetAtToOne () {
67152 // given
68- final BidRequest bidRequest = BidRequest .builder ().build ();
153+ final BidRequest bidRequest = BidRequest .builder ()
154+ .imp (singletonList (givenImp ("zone123" )))
155+ .build ();
69156
70157 // when
71158 final Result <List <HttpRequest <BidRequest >>> result = target .makeHttpRequests (bidRequest );
@@ -160,6 +247,105 @@ public void makeBidsShouldReturnBannerBidIfVideoIsAbsentInRequestImp() throws Js
160247 .containsOnly (BidderBid .of (Bid .builder ().impid ("123" ).build (), banner , null ));
161248 }
162249
250+ @ Test
251+ public void makeBidsShouldReturnMultipleBidsFromSingleSeatBid () throws JsonProcessingException {
252+ // given
253+ final BidderCall <BidRequest > httpCall = givenHttpCall (
254+ BidRequest .builder ()
255+ .imp (List .of (
256+ Imp .builder ().id ("123" ).build (),
257+ Imp .builder ().id ("456" ).video (Video .builder ().build ()).build ()))
258+ .build (),
259+ mapper .writeValueAsString (
260+ BidResponse .builder ()
261+ .cur ("USD" )
262+ .seatbid (singletonList (SeatBid .builder ()
263+ .bid (List .of (
264+ Bid .builder ().impid ("123" ).price (BigDecimal .valueOf (1.0 )).build (),
265+ Bid .builder ().impid ("456" ).price (BigDecimal .valueOf (2.0 )).build ()))
266+ .build ()))
267+ .build ()));
268+
269+ // when
270+ final Result <List <BidderBid >> result = target .makeBids (httpCall , null );
271+
272+ // then
273+ assertThat (result .getErrors ()).isEmpty ();
274+ assertThat (result .getValue ()).hasSize (2 )
275+ .containsExactlyInAnyOrder (
276+ BidderBid .of (Bid .builder ().impid ("123" ).price (BigDecimal .valueOf (1.0 )).build (), banner , "USD" ),
277+ BidderBid .of (Bid .builder ().impid ("456" ).price (BigDecimal .valueOf (2.0 )).build (), video , "USD" ));
278+ }
279+
280+ @ Test
281+ public void makeBidsShouldFilterNullBids () throws JsonProcessingException {
282+ // given
283+ final BidderCall <BidRequest > httpCall = givenHttpCall (
284+ BidRequest .builder ()
285+ .imp (singletonList (Imp .builder ().id ("123" ).build ()))
286+ .build (),
287+ mapper .writeValueAsString (
288+ BidResponse .builder ()
289+ .seatbid (singletonList (SeatBid .builder ()
290+ .bid (Arrays .asList (
291+ Bid .builder ().impid ("123" ).build (),
292+ null ,
293+ Bid .builder ().impid ("456" ).build ()))
294+ .build ()))
295+ .build ()));
296+
297+ // when
298+ final Result <List <BidderBid >> result = target .makeBids (httpCall , null );
299+
300+ // then
301+ assertThat (result .getErrors ()).isEmpty ();
302+ assertThat (result .getValue ()).hasSize (2 )
303+ .extracting (BidderBid ::getBid )
304+ .extracting (Bid ::getImpid )
305+ .containsExactlyInAnyOrder ("123" , "456" );
306+ }
307+
308+ @ Test
309+ public void makeBidsShouldReturnBidWithCurrency () throws JsonProcessingException {
310+ // given
311+ final BidderCall <BidRequest > httpCall = givenHttpCall (
312+ BidRequest .builder ()
313+ .imp (singletonList (Imp .builder ().id ("123" ).build ()))
314+ .build (),
315+ mapper .writeValueAsString (
316+ BidResponse .builder ()
317+ .cur ("EUR" )
318+ .seatbid (singletonList (SeatBid .builder ()
319+ .bid (singletonList (Bid .builder ().impid ("123" ).build ()))
320+ .build ()))
321+ .build ()));
322+
323+ // when
324+ final Result <List <BidderBid >> result = target .makeBids (httpCall , null );
325+
326+ // then
327+ assertThat (result .getErrors ()).isEmpty ();
328+ assertThat (result .getValue ())
329+ .extracting (BidderBid ::getBidCurrency )
330+ .containsExactly ("EUR" );
331+ }
332+
333+ @ Test
334+ public void makeBidsShouldReturnEmptyListIfSeatBidIsEmpty () throws JsonProcessingException {
335+ // given
336+ final BidderCall <BidRequest > httpCall = givenHttpCall (null ,
337+ mapper .writeValueAsString (BidResponse .builder ()
338+ .seatbid (singletonList (SeatBid .builder ().build ()))
339+ .build ()));
340+
341+ // when
342+ final Result <List <BidderBid >> result = target .makeBids (httpCall , null );
343+
344+ // then
345+ assertThat (result .getErrors ()).isEmpty ();
346+ assertThat (result .getValue ()).isEmpty ();
347+ }
348+
163349 private static BidResponse givenBidResponse (Function <Bid .BidBuilder , Bid .BidBuilder > bidCustomizer ) {
164350 return BidResponse .builder ()
165351 .seatbid (singletonList (SeatBid .builder ().bid (singletonList (bidCustomizer .apply (Bid .builder ()).build ()))
@@ -173,4 +359,11 @@ private static BidderCall<BidRequest> givenHttpCall(BidRequest bidRequest, Strin
173359 HttpResponse .of (200 , null , body ),
174360 null );
175361 }
362+
363+ private static Imp givenImp (String zoneId ) {
364+ return Imp .builder ()
365+ .id ("123" )
366+ .ext (mapper .valueToTree (ExtPrebid .of (null , ExtImpSmilewanted .of (zoneId ))))
367+ .build ();
368+ }
176369}
0 commit comments