From a5365df9ef51a7a20a3cc469c0de00bb78931793 Mon Sep 17 00:00:00 2001 From: youssef Date: Wed, 20 May 2026 16:02:58 +0100 Subject: [PATCH 1/5] Align Missena adapter request payload with PBS Go --- .../bidder/missena/MissenaAdRequest.java | 7 ++++ .../server/bidder/missena/MissenaBidder.java | 15 ++++++++- .../bidder/missena/MissenaUserParams.java | 9 +++--- .../ext/request/missena/ExtImpMissena.java | 3 +- .../static/bidder-params/missena.json | 6 ++-- .../bidder/missena/MissenaBidderTest.java | 32 +++++++++++++++---- .../missena/test-auction-missena-request.json | 2 +- .../missena/test-missena-bid-request.json | 5 +-- 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java b/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java index 2f9722b2c82..f01c6a81e79 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java @@ -2,10 +2,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Eid; import lombok.Builder; import lombok.Value; import java.math.BigDecimal; +import java.util.List; @Value @Builder(toBuilder = true) @@ -16,6 +18,11 @@ public class MissenaAdRequest { String currency; + Boolean debug; + + @JsonProperty("userEids") + List userEids; + BigDecimal floor; String floorCurrency; diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index eacc3a49541..074297d242e 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -3,11 +3,14 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -21,6 +24,7 @@ import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtUser; import org.prebid.server.proto.openrtb.ext.request.missena.ExtImpMissena; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; @@ -91,15 +95,18 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im final Price floorInfo = resolveBidFloor(imp, request, requestCurrency); final MissenaUserParams userParams = MissenaUserParams.builder() + .apiKey(extImp.getApiKey()) .formats(extImp.getFormats()) .placement(extImp.getPlacement()) - .testMode(extImp.getTestMode()) + .sample(extImp.getSample()) .settings(extImp.getSettings()) .build(); final MissenaAdRequest missenaAdRequest = MissenaAdRequest.builder() .adUnit(imp.getId()) .currency(requestCurrency) + .debug(Objects.equals(request.getTest(), 1) ? Boolean.TRUE : null) + .userEids(resolveUserEids(request.getUser())) .floor(floorInfo.getValue()) .floorCurrency(floorInfo.getCurrency()) .idempotencyKey(request.getId()) @@ -120,6 +127,12 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im .build(); } + private static List resolveUserEids(User user) { + final ExtUser extUser = user != null ? user.getExt() : null; + final List eids = extUser != null ? extUser.getEids() : null; + return CollectionUtils.isNotEmpty(eids) ? eids : null; + } + private Price resolveBidFloor(Imp imp, BidRequest bidRequest, String targetCurrency) { final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); return BidderUtil.isValidPrice(initialBidFloorPrice) diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java b/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java index e63a704a60c..bc97b9242bc 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java @@ -1,7 +1,7 @@ package org.prebid.server.bidder.missena; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.node.ObjectNode; // Changed import +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Builder; import lombok.Value; @@ -11,13 +11,14 @@ @Value public class MissenaUserParams { + @JsonProperty("apiKey") + String apiKey; + List formats; String placement; - @JsonProperty("test") - String testMode; + String sample; ObjectNode settings; } - diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java index 0c3a8fd08ab..bf11d296186 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java @@ -18,8 +18,7 @@ public class ExtImpMissena { String placement; - @JsonProperty("test") - String testMode; + String sample; ObjectNode settings; } diff --git a/src/main/resources/static/bidder-params/missena.json b/src/main/resources/static/bidder-params/missena.json index be5217efdb1..69d0291cc36 100644 --- a/src/main/resources/static/bidder-params/missena.json +++ b/src/main/resources/static/bidder-params/missena.json @@ -13,9 +13,9 @@ "type": "string", "description": "Placement Type (Sticky, Header, ...)" }, - "test": { - "type": "string", - "description": "Test Mode" + "sample": { + "type": ["string", "null"], + "description": "Sample" }, "formats": { "type": "array", diff --git a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java index e7a636fc4bb..38655720b5d 100644 --- a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java @@ -1,14 +1,17 @@ package org.prebid.server.bidder.missena; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Regs; import com.iab.openrtb.request.Site; import com.iab.openrtb.request.Source; import com.iab.openrtb.request.SupplyChain; +import com.iab.openrtb.request.Uid; import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; import org.junit.jupiter.api.BeforeEach; @@ -32,6 +35,7 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.version.PrebidVersionProvider; +import java.io.IOException; import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; @@ -95,23 +99,29 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { } @Test - public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { + public void makeHttpRequestsShouldMakeRequestForFirstValidImp() throws IOException { // given final ObjectNode settingsNode = mapper.createObjectNode().put("settingKey", "settingValue"); + final List userEids = List.of(Eid.builder() + .source("id-source") + .uids(List.of(Uid.builder().id("uid").atype(1).build())) + .build()); final BidRequest bidRequest = BidRequest.builder() .id("requestId") + .test(1) .tmax(500L) .cur(singletonList("USD")) .imp(List.of( givenImp(imp -> imp.id("impId1") - .ext(givenImpExt("apiKey1", "placementId1", "1", List.of("banner"), settingsNode))), + .ext(givenImpExt("apiKey1", "placementId1", "sample1", + List.of("banner"), settingsNode))), givenImp(imp -> imp.id("impId2") - .ext(givenImpExt("apiKey2", "placementId2", "0", null, null))))) + .ext(givenImpExt("apiKey2", "placementId2", "sample2", null, null))))) .site(Site.builder().page("http://test.com/page").domain("test.com").build()) .regs(Regs.builder().ext(ExtRegs.of(1, null, null, null)).build()) .user(User.builder().buyeruid("buyer1") - .ext(ExtUser.builder().consent("consentStr").build()).build()) + .ext(ExtUser.builder().consent("consentStr").eids(userEids).build()).build()) .source(Source.builder().schain(SupplyChain.of(1, null, null, null)).build()) .device(Device.builder().ua("test-ua").ip("123.123.123.123").build()) .build(); @@ -121,15 +131,18 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { // then final MissenaUserParams expectedUserParams = MissenaUserParams.builder() + .apiKey("apiKey1") .formats(List.of("banner")) .placement("placementId1") - .testMode("1") + .sample("sample1") .settings(settingsNode) .build(); final MissenaAdRequest expectedPayload = MissenaAdRequest.builder() .adUnit("impId1") .currency("USD") + .debug(true) + .userEids(userEids) .floor(BigDecimal.valueOf(0.1)) .floorCurrency("USD") .idempotencyKey("requestId") @@ -147,6 +160,11 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { assertThat(result.getValue()) .extracting(HttpRequest::getImpIds) .containsExactly(Collections.singleton("impId1")); + + final JsonNode body = mapper.readTree(result.getValue().getFirst().getBody()); + assertThat(body.at("/params/apiKey").asText()).isEqualTo("apiKey1"); + assertThat(body.at("/debug").asBoolean()).isTrue(); + assertThat(body.at("/userEids/0/source").asText()).isEqualTo("id-source"); } @Test @@ -326,14 +344,14 @@ private static ObjectNode givenImpExt(String apiKey) { private static ObjectNode givenImpExt(String apiKey, String placement, - String testMode, + String sample, List formats, ObjectNode settings) { final ExtImpMissena extImpMissena = ExtImpMissena.builder() .apiKey(apiKey) .placement(placement) - .testMode(testMode) + .sample(sample) .formats(formats) .settings(settings) .build(); diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json index cacda5b188c..89c82b49442 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json @@ -11,7 +11,7 @@ "missena": { "apiKey": "apiKey", "placement": "placement", - "test": "test" + "sample": "sample" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json index 0901179a05d..d280b4f4994 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json @@ -5,8 +5,9 @@ "request_id" : "request_id", "timeout" : "${json-unit.any-number}", "params" : { + "apiKey" : "apiKey", "placement" : "placement", - "test" : "test" + "sample" : "sample" }, "ortb2" : { "id" : "request_id", @@ -22,7 +23,7 @@ "bidder" : { "apiKey" : "apiKey", "placement" : "placement", - "test" : "test" + "sample" : "sample" } } } ], From 9b6b390761d91b9b83575a4f782a9069a0cec7e7 Mon Sep 17 00:00:00 2001 From: youssef Date: Thu, 18 Jun 2026 15:11:17 +0100 Subject: [PATCH 2/5] Add separate tests for Missena request passthrough logic --- .../bidder/missena/MissenaBidderTest.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java index 38655720b5d..48d0ce8de67 100644 --- a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java @@ -167,6 +167,121 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() throws IOExcepti assertThat(body.at("/userEids/0/source").asText()).isEqualTo("id-source"); } + @Test + public void makeHttpRequestsShouldPassOriginalBidRequestAsOrtb2() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getBidRequest) + .isEqualTo(bidRequest); + } + + @Test + public void makeHttpRequestsShouldPassUserEidsWhenPresent() { + // given + final List userEids = List.of(Eid.builder() + .source("id-source") + .uids(List.of(Uid.builder().id("uid").atype(1).build())) + .build()); + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) + .toBuilder() + .user(User.builder().ext(ExtUser.builder().eids(userEids).build()).build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isEqualTo(userEids); + } + + @Test + public void makeHttpRequestsShouldNotPassUserEidsWhenUserIsNull() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) + .toBuilder() + .user(null) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldNotPassUserEidsWhenEidsAreEmpty() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) + .toBuilder() + .user(User.builder().ext(ExtUser.builder().eids(Collections.emptyList()).build()).build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldSetDebugWhenTestIsOne() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) + .toBuilder() + .test(1) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getDebug) + .isEqualTo(true); + } + + @Test + public void makeHttpRequestsShouldNotSetDebugWhenTestIsNotOne() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) + .toBuilder() + .test(0) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getDebug) + .isNull(); + } + @Test public void makeHttpRequestsShouldReturnErrorIfAllImpsAreInvalid() { // given From 378b8092103456016b0a51607323ef85bc223b82 Mon Sep 17 00:00:00 2001 From: youssef Date: Wed, 29 Jul 2026 17:53:33 +0100 Subject: [PATCH 3/5] Set Missena bid size from ad server response The adapter built bids without w/h, so every bid tripped creative size validation with size 'nullxnull' and produced no hb_size targeting. The Missena ad server already returns width and height in the response body; parse them and map them onto the bid. --- .../bidder/missena/MissenaAdResponse.java | 4 +++ .../server/bidder/missena/MissenaBidder.java | 2 ++ .../bidder/missena/MissenaBidderTest.java | 29 +++++++++++++++++++ .../test-auction-missena-response.json | 2 ++ .../missena/test-missena-bid-response.json | 4 ++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java b/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java index 6a34c31efbf..acec2fa0199 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java @@ -16,6 +16,10 @@ public class MissenaAdResponse { String currency; + Integer width; + + Integer height; + @JsonProperty("requestId") String requestId; } diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index 074297d242e..776843ed419 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -215,6 +215,8 @@ private BidderBid extractBid(BidRequest request, MissenaAdResponse response) { .impid(request.getImp().getFirst().getId()) .adm(response.getAd()) .crid(response.getRequestId()) + .w(response.getWidth()) + .h(response.getHeight()) .build(); return BidderBid.of(bid, BidType.banner, response.getCurrency()); diff --git a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java index 48d0ce8de67..2a5f5911a53 100644 --- a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java @@ -45,6 +45,7 @@ import static java.util.Collections.singletonList; import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; @@ -414,6 +415,8 @@ public void makeBidsShouldReturnSingleBid() throws JsonProcessingException { .cpm(BigDecimal.TEN) .currency("USD") .ad("adm") + .width(320) + .height(100) .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); @@ -431,12 +434,38 @@ public void makeBidsShouldReturnSingleBid() throws JsonProcessingException { .price(BigDecimal.TEN) .adm("adm") .crid("id") + .w(320) + .h(100) .build(); assertThat(result.getValue()).hasSize(1) .containsOnly(BidderBid.of(expectedBid, BidType.banner, "USD")); } + @Test + public void makeBidsShouldReturnBidWithoutSizeWhenResponseHasNoSize() throws JsonProcessingException { + // given + final MissenaAdResponse bidResponse = MissenaAdResponse.builder() + .requestId("id") + .cpm(BigDecimal.TEN) + .currency("USD") + .ad("adm") + .build(); + + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId")).toBuilder().id("requestId").build(); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getW, Bid::getH) + .containsExactly(tuple(null, null)); + } + private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { final List imps = Arrays.stream(impCustomizers) .map(MissenaBidderTest::givenImp) diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json index 344c58cb6e6..4b0511cc829 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json @@ -10,6 +10,8 @@ "price": 10.2, "adm": "adm", "crid": "id", + "w": 320, + "h": 250, "ext": { "origbidcpm": 10.2, "origbidcur": "USD", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json index 4dece3dba9b..1c4c0cbfacd 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json @@ -2,5 +2,7 @@ "requestId": "id", "cpm": 10.2, "ad": "adm", - "currency": "USD" + "currency": "USD", + "width": 320, + "height": 250 } From 81447719d79bb103185c81a30e838590a97252ba Mon Sep 17 00:00:00 2001 From: youssef Date: Thu, 13 Aug 2026 16:43:01 +0100 Subject: [PATCH 4/5] Missena: address review feedback Send the version as `prebid-server-java@` to follow the `name@version` convention the bid server already receives from Prebid.js (`prebid.js@`) and Prebid Server Go (`prebid-server@`), while keeping Go and Java traffic distinguishable. Falls back to `prebid-server-java@unknown` when the version record is unavailable. Drop the JSON body assertions in makeHttpRequestsShouldMakeRequestForFirstValidImp; the preceding containsExactly(expectedPayload) already compares the whole payload, so they were redundant. Add givenBidRequest(UnaryOperator, Imp...) and use it in place of givenBidRequest(...).toBuilder(). The existing imp-customizer overload is replaced by givenBidRequest(Imp...) as in VisibleMeasuresBidderTest, since two overloads both taking a lambda first are ambiguous at the call site. --- .../server/bidder/missena/MissenaBidder.java | 13 +- .../bidder/missena/MissenaBidderTest.java | 120 ++++++++++-------- 2 files changed, 78 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index 772e1190a37..8a115c40424 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -46,6 +46,9 @@ public class MissenaBidder implements Bidder { private static final String USD_CURRENCY = "USD"; private static final String EUR_CURRENCY = "EUR"; private static final String PUBLISHER_ID_MACRO = "PublisherID"; + private static final String VERSION_NAME = "prebid-server-java"; + private static final String VERSION_UNKNOWN = "unknown"; + private static final String VERSION_SEPARATOR = "@"; private final Uri endpointUrl; private final JacksonMapper mapper; @@ -113,7 +116,7 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im .requestId(request.getId()) .timeout(request.getTmax()) .params(userParams) - .version(prebidVersionProvider.getNameVersionRecord()) + .version(resolveVersion()) .bidRequest(request) .build(); @@ -127,6 +130,14 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im .build(); } + // The Missena bid server expects a "name@version" record: Prebid.js sends "prebid.js@" and Prebid Server + // Go sends "prebid-server@". PrebidVersionProvider yields "pbs-java/", so reshape it here to + // follow that convention while keeping Go and Java traffic distinguishable. + private String resolveVersion() { + final String version = StringUtils.substringAfter(prebidVersionProvider.getNameVersionRecord(), "/"); + return VERSION_NAME + VERSION_SEPARATOR + (StringUtils.isNotEmpty(version) ? version : VERSION_UNKNOWN); + } + private static List resolveUserEids(User user) { final ExtUser extUser = user != null ? user.getExt() : null; final List eids = extUser != null ? extUser.getEids() : null; diff --git a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java index 2d6bd001bd6..441e1700023 100644 --- a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java @@ -1,7 +1,6 @@ package org.prebid.server.bidder.missena; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; @@ -35,9 +34,7 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.version.PrebidVersionProvider; -import java.io.IOException; import java.math.BigDecimal; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.UnaryOperator; @@ -62,7 +59,8 @@ class MissenaBidderTest extends VertxTest { private static final String ENDPOINT_URL = "https://test-url.com/?t={PublisherID}"; - private static final String TEST_PBS_VERSION = "pbs-java/1.0"; + private static final String TEST_PBS_VERSION_RECORD = "pbs-java/1.0"; + private static final String TEST_EXPECTED_VERSION = "prebid-server-java@1.0"; @Mock(strictness = LENIENT) private CurrencyConversionService currencyConversionService; @@ -80,7 +78,7 @@ public void setUp() { currencyConversionService, prebidVersionProvider); - given(prebidVersionProvider.getNameVersionRecord()).willReturn(TEST_PBS_VERSION); + given(prebidVersionProvider.getNameVersionRecord()).willReturn(TEST_PBS_VERSION_RECORD); given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) .willAnswer(invocation -> invocation.getArgument(0)); } @@ -88,7 +86,7 @@ public void setUp() { @Test public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenInvalidImpExt())); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenInvalidImpExt()))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -100,7 +98,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { } @Test - public void makeHttpRequestsShouldMakeRequestForFirstValidImp() throws IOException { + public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { // given final ObjectNode settingsNode = mapper.createObjectNode().put("settingKey", "settingValue"); final List userEids = List.of(Eid.builder() @@ -150,7 +148,7 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() throws IOExcepti .requestId("requestId") .timeout(500L) .params(expectedUserParams) - .version(TEST_PBS_VERSION) + .version(TEST_EXPECTED_VERSION) .bidRequest(bidRequest) .build(); @@ -161,17 +159,12 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() throws IOExcepti assertThat(result.getValue()) .extracting(HttpRequest::getImpIds) .containsExactly(Collections.singleton("impId1")); - - final JsonNode body = mapper.readTree(result.getValue().getFirst().getBody()); - assertThat(body.at("/params/apiKey").asText()).isEqualTo("apiKey1"); - assertThat(body.at("/debug").asBoolean()).isTrue(); - assertThat(body.at("/userEids/0/source").asText()).isEqualTo("id-source"); } @Test public void makeHttpRequestsShouldPassOriginalBidRequestAsOrtb2() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -191,10 +184,9 @@ public void makeHttpRequestsShouldPassUserEidsWhenPresent() { .source("id-source") .uids(List.of(Uid.builder().id("uid").atype(1).build())) .build()); - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) - .toBuilder() - .user(User.builder().ext(ExtUser.builder().eids(userEids).build()).build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().ext(ExtUser.builder().eids(userEids).build()).build()), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -210,10 +202,9 @@ public void makeHttpRequestsShouldPassUserEidsWhenPresent() { @Test public void makeHttpRequestsShouldNotPassUserEidsWhenUserIsNull() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) - .toBuilder() - .user(null) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.user(null), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -229,10 +220,10 @@ public void makeHttpRequestsShouldNotPassUserEidsWhenUserIsNull() { @Test public void makeHttpRequestsShouldNotPassUserEidsWhenEidsAreEmpty() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) - .toBuilder() - .user(User.builder().ext(ExtUser.builder().eids(Collections.emptyList()).build()).build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.user( + User.builder().ext(ExtUser.builder().eids(Collections.emptyList()).build()).build()), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -248,10 +239,9 @@ public void makeHttpRequestsShouldNotPassUserEidsWhenEidsAreEmpty() { @Test public void makeHttpRequestsShouldSetDebugWhenTestIsOne() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) - .toBuilder() - .test(1) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.test(1), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -267,10 +257,9 @@ public void makeHttpRequestsShouldSetDebugWhenTestIsOne() { @Test public void makeHttpRequestsShouldNotSetDebugWhenTestIsNotOne() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("apiKey"))) - .toBuilder() - .test(0) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.test(0), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -283,12 +272,29 @@ public void makeHttpRequestsShouldNotSetDebugWhenTestIsNotOne() { .isNull(); } + @Test + public void makeHttpRequestsShouldSendUnknownVersionWhenVersionRecordIsNull() { + // given + given(prebidVersionProvider.getNameVersionRecord()).willReturn(null); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getVersion) + .isEqualTo("prebid-server-java@unknown"); + } + @Test public void makeHttpRequestsShouldReturnErrorIfAllImpsAreInvalid() { // given final BidRequest bidRequest = givenBidRequest( - imp -> imp.ext(givenInvalidImpExt()), - imp -> imp.ext(givenInvalidImpExt())); + givenImp(imp -> imp.ext(givenInvalidImpExt())), + givenImp(imp -> imp.ext(givenInvalidImpExt()))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -303,11 +309,11 @@ public void makeHttpRequestsShouldReturnErrorIfAllImpsAreInvalid() { @Test public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpAndIpv6() { // given - final BidRequest bidRequest = givenBidRequest(identity()) - .toBuilder() - .site(Site.builder().page("http://page.com").build()) - .device(Device.builder().ua("ua").ip("ip").ipv6("ipv6").build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request + .site(Site.builder().page("http://page.com").build()) + .device(Device.builder().ua("ua").ip("ip").ipv6("ipv6").build()), + givenImp(identity())); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -329,10 +335,9 @@ public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpAndIpv6() @Test public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpv6Only() { // given - final BidRequest bidRequest = givenBidRequest(identity()) - .toBuilder() - .device(Device.builder().ip(null).ipv6("ipv6").build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip(null).ipv6("ipv6").build()), + givenImp(identity())); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -378,7 +383,7 @@ public void makeHttpRequestsShouldConvertBidFloorCurrency() { @Test public void makeHttpRequestsShouldUseCorrectUri() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("testApiKey"))); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("testApiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -394,7 +399,7 @@ public void makeHttpRequestsShouldUseCorrectUri() { public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given final BidderCall httpCall = givenHttpCall("invalid"); - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId1")); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("impId1"))); // when final Result> result = target.makeBids(httpCall, bidRequest); @@ -420,7 +425,9 @@ public void makeBidsShouldReturnSingleBid() throws JsonProcessingException { .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId")).toBuilder().id("requestId").build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.id("requestId"), + givenImp(imp -> imp.id("impId"))); // when final Result> result = target.makeBids(httpCall, bidRequest); @@ -453,7 +460,9 @@ public void makeBidsShouldReturnBidWithoutSizeWhenResponseHasNoSize() throws Jso .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId")).toBuilder().id("requestId").build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.id("requestId"), + givenImp(imp -> imp.id("impId"))); // when final Result> result = target.makeBids(httpCall, bidRequest); @@ -466,11 +475,14 @@ public void makeBidsShouldReturnBidWithoutSizeWhenResponseHasNoSize() throws Jso .containsExactly(tuple(null, null)); } - private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { - final List imps = Arrays.stream(impCustomizers) - .map(MissenaBidderTest::givenImp) - .toList(); - return BidRequest.builder().imp(imps).cur(singletonList("USD")).build(); + private static BidRequest givenBidRequest(Imp... imps) { + return givenBidRequest(identity(), imps); + } + + private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, + Imp... imps) { + + return bidRequestCustomizer.apply(BidRequest.builder().imp(List.of(imps)).cur(singletonList("USD"))).build(); } private static Imp givenImp(UnaryOperator impCustomizer) { From 27fce1992621400149f28c619f2130876b4e7c0b Mon Sep 17 00:00:00 2001 From: youssef Date: Thu, 13 Aug 2026 17:23:14 +0100 Subject: [PATCH 5/5] Missena: drop explanatory comment on resolveVersion --- .../java/org/prebid/server/bidder/missena/MissenaBidder.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index 8a115c40424..1194d57444e 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -130,9 +130,6 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im .build(); } - // The Missena bid server expects a "name@version" record: Prebid.js sends "prebid.js@" and Prebid Server - // Go sends "prebid-server@". PrebidVersionProvider yields "pbs-java/", so reshape it here to - // follow that convention while keeping Go and Java traffic distinguishable. private String resolveVersion() { final String version = StringUtils.substringAfter(prebidVersionProvider.getNameVersionRecord(), "/"); return VERSION_NAME + VERSION_SEPARATOR + (StringUtils.isNotEmpty(version) ? version : VERSION_UNKNOWN);