Skip to content

Commit

Permalink
Stroeercore: Allow video traffic (prebid#2691)
Browse files Browse the repository at this point in the history
  • Loading branch information
docech authored Oct 13, 2023
1 parent 51ffe0b commit 6f298ef
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest bidRequ
}

private static void validateImp(Imp imp) {
if (imp.getBanner() == null) {
throw new PreBidException("Expected banner impression");
if (imp.getBanner() == null && imp.getVideo() == null) {
throw new PreBidException("Expected banner or video impression");
}
}

Expand Down Expand Up @@ -137,36 +137,50 @@ private static Imp modifyImp(Imp imp, ExtImpStroeerCore impExt, Price price) {
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
try {
final String body = httpCall.getResponse().getBody();
final StroeerCoreBidResponse response = mapper.decodeValue(body, StroeerCoreBidResponse.class);
return Result.withValues(extractBids(response));
final StroeerCoreBidResponse bidResponse = mapper.decodeValue(body, StroeerCoreBidResponse.class);
return Result.withValues(extractBids(httpCall.getRequest().getPayload(), bidResponse));
} catch (DecodeException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}
}

private static List<BidderBid> extractBids(StroeerCoreBidResponse bidResponse) {
private static List<BidderBid> extractBids(BidRequest bidRequest, StroeerCoreBidResponse bidResponse) {
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getBids())) {
return Collections.emptyList();
}

return bidResponse.getBids().stream()
.filter(Objects::nonNull)
.map(StroeerCoreBidder::toBidderBid)
.map(stroeerCoreBid -> toBidderBid(bidRequest, stroeerCoreBid))
.toList();
}

private static BidderBid toBidderBid(StroeerCoreBid stroeercoreBid) {
private static BidderBid toBidderBid(BidRequest bidRequest, StroeerCoreBid stroeercoreBid) {
return BidderBid.of(
Bid.builder()
.id(stroeercoreBid.getId())
.impid(stroeercoreBid.getBidId())
.impid(stroeercoreBid.getImpId())
.w(stroeercoreBid.getWidth())
.h(stroeercoreBid.getHeight())
.price(stroeercoreBid.getCpm())
.adm(stroeercoreBid.getAdMarkup())
.crid(stroeercoreBid.getCreativeId())
.build(),
BidType.banner,
getBidType(stroeercoreBid.getImpId(), bidRequest.getImp()),
BIDDER_CURRENCY);
}

private static BidType getBidType(String impId, List<Imp> imps) {
for (Imp imp : imps) {
if (imp.getId().equals(impId)) {
if (imp.getBanner() != null) {
return BidType.banner;
} else if (imp.getVideo() != null) {
return BidType.video;
}
}
}

return BidType.banner;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class StroeerCoreBid {
String id;

@JsonProperty("bidId")
String bidId;
String impId;

BigDecimal cpm;

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/bidder-config/stroeercore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ adapters:
maintainer-email: [email protected]
app-media-types:
- banner
- video
site-media-types:
- banner
- video
supported-vendors:
vendor-id: 136
usersync:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.Audio;
import com.iab.openrtb.request.Banner;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
Expand Down Expand Up @@ -143,17 +144,17 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() {
}

@Test
public void makeHttpRequestsShouldReturnErrorWhenImpHasNoBanner() {
public void makeHttpRequestsShouldReturnErrorWhenImpHasNoBannerOrVideo() {
// given
final BidRequest invalidBidRequest = createBidRequest(createVideoImp("123", imp -> imp.id("2")));
final BidRequest invalidBidRequest = createBidRequest(createAudioImp("123", imp -> imp.id("2")));

// when
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(invalidBidRequest);

// then
assertThat(result.getValue()).isEmpty();
assertThat(result.getErrors())
.containsExactly(BidderError.badInput("Expected banner impression. Ignore imp id = 2."));
.containsExactly(BidderError.badInput("Expected banner or video impression. Ignore imp id = 2."));
}

@Test
Expand All @@ -178,7 +179,8 @@ public void makeHttpRequestsShouldIgnoreInvalidImpressions() {
createBannerImp(" "),
createBannerImp("a"),
createBannerImp("b", imp -> imp.banner(null)),
createVideoImp("c", identity()),
createAudioImp("not-supported", identity()),
createVideoImp("c"),
createBannerImp("d"),
createBannerImp("e", imp -> imp.bidfloor(BigDecimal.ONE).bidfloorcur("GPB")));

Expand All @@ -196,7 +198,7 @@ public void makeHttpRequestsShouldIgnoreInvalidImpressions() {
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getTagid)
.containsExactly("a", "d");
.containsExactly("a", "c", "d");
}

@Test
Expand Down Expand Up @@ -225,7 +227,7 @@ public void makeHttpRequestsShouldConvertCurrencyToEuro() {
}

@Test
public void makeHttpRequestsShouldIgnoreBidIfCurrencyIfCurrencyServiceThrowsException() {
public void makeHttpRequestsShouldIgnoreBidIfCurrencyServiceThrowsException() {
// given
final BigDecimal usdBidFloor = BigDecimal.valueOf(0.5);
final Imp usdImp = createBannerImp("10", imp -> imp.id("1282").bidfloorcur("USD").bidfloor(usdBidFloor));
Expand All @@ -249,64 +251,64 @@ public void makeHttpRequestsShouldIgnoreBidIfCurrencyIfCurrencyServiceThrowsExce
}

@Test
public void makeBidsShouldReturnExpectedBidderBids() throws JsonProcessingException {
public void makeBidsShouldReturnExpectedBidderBidsWithProperBidType() throws JsonProcessingException {
// given
final StroeerCoreBid bid1 = StroeerCoreBid.builder()
final Imp bannerImp = createBannerImp("banner-slot-id", impBuilder -> impBuilder.id("banner-imp-id"));
final Imp videoImp = createVideoImp("video-slot-id", impBuilder -> impBuilder.id("video-imp-id"));
final BidRequest bidRequest = createBidRequest(bannerImp, videoImp);

final StroeerCoreBid bannerBid = StroeerCoreBid.builder()
.id("1")
.bidId("1929")
.impId("banner-imp-id")
.adMarkup("<div></div>")
.cpm(BigDecimal.valueOf(0.3))
.creativeId("foo")
.width(300)
.height(600)
.build();

final StroeerCoreBid bid2 = StroeerCoreBid.builder()
final StroeerCoreBid videoBid = StroeerCoreBid.builder()
.id("27")
.bidId("2010")
.adMarkup("<span></span>")
.impId("video-imp-id")
.adMarkup("<vast><span></span></vast>")
.cpm(BigDecimal.valueOf(1.58))
.creativeId("bar")
.width(800)
.height(250)
.creativeId("vid")
.build();

final StroeerCoreBidResponse response = StroeerCoreBidResponse.of(List.of(bid1, bid2));
final BidderCall<BidRequest> httpCall = createHttpCall(response);
final StroeerCoreBidResponse response = StroeerCoreBidResponse.of(List.of(bannerBid, videoBid));
final BidderCall<BidRequest> httpCall = createHttpCall(bidRequest, response);

// when
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
final Result<List<BidderBid>> result = target.makeBids(httpCall, bidRequest);

// then
final Bid expectedBid1 = Bid.builder()
final Bid expectedBannerBid = Bid.builder()
.id("1")
.impid("1929")
.impid("banner-imp-id")
.adm("<div></div>")
.price(BigDecimal.valueOf(0.3))
.crid("foo")
.w(300)
.h(600)
.build();

final Bid expectedBid2 = Bid.builder()
final Bid expectedVideoBid = Bid.builder()
.id("27")
.impid("2010")
.adm("<span></span>")
.impid("video-imp-id")
.adm("<vast><span></span></vast>")
.price(BigDecimal.valueOf(1.58))
.crid("bar")
.w(800)
.h(250)
.crid("vid")
.build();

assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue()).containsOnly(BidderBid.of(expectedBid1, BidType.banner, "EUR"),
BidderBid.of(expectedBid2, BidType.banner, "EUR"));
assertThat(result.getValue()).containsOnly(BidderBid.of(expectedBannerBid, BidType.banner, "EUR"),
BidderBid.of(expectedVideoBid, BidType.video, "EUR"));
}

@Test
public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() {
// given
final BidderCall<BidRequest> httpCall = createHttpCall("[]");
final BidderCall<BidRequest> httpCall = createHttpCallWithNonParsableResponse();

// when
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
Expand All @@ -322,7 +324,8 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() {
@Test
public void makeBidsShouldReturnEmptyListIfZeroBids() throws JsonProcessingException {
// given
final BidderCall<BidRequest> httpCall = createHttpCall(StroeerCoreBidResponse.of(emptyList()));
final BidderCall<BidRequest> httpCall = createHttpCall(BidRequest.builder().build(),
StroeerCoreBidResponse.of(emptyList()));

// when
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
Expand Down Expand Up @@ -357,6 +360,15 @@ private Imp createVideoImp(String slotId, UnaryOperator<Imp.ImpBuilder> impCusto
return createImp(slotId, addVideo.andThen(impCustomizer));
}

private Imp createVideoImp(String slotId) {
return createVideoImp(slotId, identity());
}

private Imp createAudioImp(String slotId, UnaryOperator<Imp.ImpBuilder> impCustomizer) {
final UnaryOperator<ImpBuilder> addAudio = imp -> imp.audio(Audio.builder().build());
return createImp(slotId, addAudio.andThen(impCustomizer));
}

private Imp createImp(String slotId, Function<ImpBuilder, ImpBuilder> impCustomizer) {
final ObjectNode impExtNode = mapper.valueToTree(ExtPrebid.of(null, ExtImpStroeerCore.of(slotId)));

Expand All @@ -366,12 +378,18 @@ private Imp createImp(String slotId, Function<ImpBuilder, ImpBuilder> impCustomi
return addImpExt.andThen(impCustomizer).apply(impBuilder).build();
}

private BidderCall<BidRequest> createHttpCall(StroeerCoreBidResponse response) throws JsonProcessingException {
return createHttpCall(mapper.writeValueAsString(response));
private BidderCall<BidRequest> createHttpCall(BidRequest request, StroeerCoreBidResponse response)
throws JsonProcessingException {
return createHttpCall(HttpRequest.<BidRequest>builder().payload(request).build(),
HttpResponse.of(200, null, mapper.writeValueAsString(response)));
}

private BidderCall<BidRequest> createHttpCall(HttpRequest<BidRequest> request, HttpResponse response) {
return BidderCall.succeededHttp(request, response, null);
}

private BidderCall<BidRequest> createHttpCall(String body) {
return BidderCall.succeededHttp(HttpRequest.<BidRequest>builder().build(),
HttpResponse.of(200, null, body), null);
private BidderCall<BidRequest> createHttpCallWithNonParsableResponse() {
return createHttpCall(HttpRequest.<BidRequest>builder().build(),
HttpResponse.of(200, null, "[]"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "request_id",
"imp": [
{
"id": "imp_id",
"id": "imp_id_1",
"banner": {
"w": 300,
"h": 250
Expand All @@ -12,6 +12,19 @@
"sid": "slot_id"
}
}
},
{
"id": "imp_id_2",
"video": {
"mimes": ["video/mp4"],
"w": 300,
"h": 250
},
"ext": {
"stroeerCore": {
"sid": "slot_id"
}
}
}
],
"tmax": 5000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
{
"bid": [
{
"id": "bid_id",
"impid": "imp_id",
"id": "bid_id_1",
"impid": "imp_id_1",
"price": 7.713,
"adm": "<div>foo</div>",
"crid":"creative_id",
"crid":"banner_creative_id",
"w": 300,
"h": 250,
"ext": {
Expand All @@ -18,6 +18,20 @@
"type": "banner"
}
}
},
{
"id": "bid_id_2",
"impid": "imp_id_2",
"price": 6.494,
"adm": "<vast><div>video</div></vast>",
"crid":"video_creative_id",
"ext": {
"origbidcpm": 5.7,
"origbidcur": "EUR",
"prebid": {
"type": "video"
}
}
}
],
"seat": "stroeerCore",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "request_id",
"imp": [
{
"id": "imp_id",
"id": "imp_id_1",
"secure": 1,
"banner": {
"w": 300,
Expand All @@ -15,6 +15,22 @@
"sid": "slot_id"
}
}
},
{
"id": "imp_id_2",
"secure": 1,
"video": {
"mimes": ["video/mp4"],
"w": 300,
"h": 250
},
"tagid": "slot_id",
"ext": {
"tid": "${json-unit.any-string}",
"bidder": {
"sid": "slot_id"
}
}
}
],
"source": {
Expand Down
Loading

0 comments on commit 6f298ef

Please sign in to comment.