From ae9b2f20e3d7a1bf54a1012054e3cdfdebf738d9 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Mon, 27 Jan 2025 20:08:37 +0100 Subject: [PATCH 01/12] AdverxoTest does not work --- .../server/bidder/adverxo/AdverxoBidder.java | 218 ++++++++++++++++++ .../ext/request/adverxo/ExtImpAdverxo.java | 15 ++ .../bidder/AdverxoBidderConfiguration.java | 42 ++++ src/main/resources/bidder-config/adverxo.yaml | 27 +++ .../static/bidder-params/adverxo.json | 19 ++ .../bidder/adverxo/AdverxoBidderTest.java | 36 +++ .../org/prebid/server/it/AdverxoTest.java | 36 +++ .../adverxo/test-adverxo-bid-request.json | 33 +++ .../adverxo/test-adverxo-bid-response.json | 21 ++ .../adverxo/test-auction-adverxo-request.json | 33 +++ .../test-auction-adverxo-response.json | 21 ++ .../server/it/test-application.properties | 2 + 12 files changed, 503 insertions(+) create mode 100644 src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java create mode 100644 src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java create mode 100644 src/main/resources/bidder-config/adverxo.yaml create mode 100644 src/main/resources/static/bidder-params/adverxo.json create mode 100644 src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java create mode 100644 src/test/java/org/prebid/server/it/AdverxoTest.java create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java new file mode 100644 index 00000000000..3dd43e2b077 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -0,0 +1,218 @@ +package org.prebid.server.bidder.adverxo; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.vertx.core.http.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.exception.PreBidException; +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.adverxo.ExtImpAdverxo; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.HttpUtil; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class AdverxoBidder implements Bidder { + + private static final TypeReference> ADVERXO_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + private static final String DEFAULT_BID_CURRENCY = "USD"; + private static final String ADUNIT_MACROS_ENDPOINT = "{{adUnitId}}"; + private static final String AUTH_MACROS_ENDPOINT = "{{auth}}"; + private static final String PRICE_MACRO = "${AUCTION_PRICE}"; + + private final String endpointUrl; + private final JacksonMapper mapper; + private final CurrencyConversionService currencyConversionService; + + public AdverxoBidder(String endpointUrl, JacksonMapper mapper, + CurrencyConversionService currencyConversionService) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = mapper; + this.currencyConversionService = currencyConversionService; + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final List errors = new ArrayList<>(); + final List> requests = new ArrayList<>(); + + for (Imp imp : request.getImp()) { + try { + final ExtImpAdverxo extImp = parseImpExt(imp); + final String endpoint = resolveEndpoint(extImp); + final Imp modifiedImp = modifyImp(imp, request); + final BidRequest outgoingRequest = createRequest(request, modifiedImp); + + requests.add(createHttpRequest(outgoingRequest, endpoint, imp.getId())); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + } + } + + return Result.of(requests, errors); + } + + private ExtImpAdverxo parseImpExt(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), ADVERXO_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("Error parsing ext.imp.bidder: " + e.getMessage()); + } + } + + private String resolveEndpoint(ExtImpAdverxo extImpAdverxo) { + final String adUnitAsString = Optional.of(extImpAdverxo.getAdUnitId()) + .map(Object::toString) + .orElse(StringUtils.EMPTY); + final String authAsString = Optional.ofNullable(extImpAdverxo.getAuth()) + .map(Object::toString) + .orElse(StringUtils.EMPTY); + + return endpointUrl + .replace(ADUNIT_MACROS_ENDPOINT, adUnitAsString) + .replace(AUTH_MACROS_ENDPOINT, authAsString); + } + + private Imp modifyImp(Imp imp, BidRequest request) { + final BigDecimal bidFloor = imp.getBidfloor(); + final String bidFloorCur = imp.getBidfloorcur(); + + if (bidFloor != null && bidFloor.compareTo(BigDecimal.ZERO) > 0 + && StringUtils.isNotBlank(bidFloorCur) + && !StringUtils.equalsIgnoreCase(bidFloorCur, DEFAULT_BID_CURRENCY)) { + + final BigDecimal convertedPrice = currencyConversionService.convertCurrency( + bidFloor, + request, + bidFloorCur, + DEFAULT_BID_CURRENCY + ); + + return imp.toBuilder() + .bidfloor(convertedPrice) + .bidfloorcur(DEFAULT_BID_CURRENCY) + .build(); + } + return imp; + } + + private BidRequest createRequest(BidRequest originalRequest, Imp modifiedImp) { + return originalRequest.toBuilder() + .imp(Collections.singletonList(modifiedImp)) + .build(); + } + + private HttpRequest createHttpRequest(BidRequest outgoingRequest, + String endpoint, + String impId) { + return HttpRequest.builder() + .method(HttpMethod.POST) + .uri(endpoint) + .headers(HttpUtil.headers()) + .body(mapper.encodeToBytes(outgoingRequest)) + .impIds(Collections.singleton(impId)) + .payload(outgoingRequest) + .build(); + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final List bidderErrors = new ArrayList<>(); + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + return Result.withValues(extractBids(bidResponse, bidderErrors)); + } catch (DecodeException | PreBidException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private List extractBids(BidResponse bidResponse, + List bidderErrors) { + + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + final String currency = bidResponse.getCur(); + final List bidderBids = new ArrayList<>(); + + for (SeatBid seatBid : bidResponse.getSeatbid()) { + if (CollectionUtils.isEmpty(seatBid.getBid())) { + continue; + } + + for (Bid bid : seatBid.getBid()) { + final BidType bidType = getBidType(bid); + final String resolvedAdm = resolveAdmForBidType(bid, bidType); + final Bid processedBid = processBidMacros(bid, resolvedAdm); + + bidderBids.add(BidderBid.of(processedBid, bidType, currency)); + } + } + + return bidderBids; + } + + private BidType getBidType(Bid bid) { + final Integer markupType = ObjectUtils.defaultIfNull(bid.getMtype(), 0); + + return switch (markupType) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + case 4 -> BidType.xNative; + default -> throw new PreBidException( + "could not define media type for impression: " + bid.getImpid()); + }; + } + + private String resolveAdmForBidType(Bid bid, BidType bidType) { + if (bidType != BidType.xNative) { + return bid.getAdm(); + } + + try { + final JsonNode admNode = mapper.mapper().readTree(bid.getAdm()); + final JsonNode nativeNode = admNode.get("native"); + return nativeNode != null ? nativeNode.toString() : bid.getAdm(); + } catch (JsonProcessingException e) { + throw new PreBidException("Error parsing native ADM: " + e.getMessage()); + } + } + + private Bid processBidMacros(Bid bid, String adm) { + final String price = bid.getPrice() != null ? bid.getPrice().toPlainString() : "0"; + + return bid.toBuilder() + .adm(replaceMacro(adm, price)) + .nurl(replaceMacro(bid.getNurl(), price)) + .build(); + } + + private static String replaceMacro(String input, String value) { + return input != null ? input.replace(PRICE_MACRO, value) : null; + } +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java new file mode 100644 index 00000000000..e634e7b2b1a --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java @@ -0,0 +1,15 @@ +package org.prebid.server.proto.openrtb.ext.request.adverxo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor(staticName = "of") +public class ExtImpAdverxo { + + @JsonProperty("adUnitId") + int adUnitId; + @JsonProperty("auth") + String auth; +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java new file mode 100644 index 00000000000..f1a66b21e4e --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java @@ -0,0 +1,42 @@ +package org.prebid.server.spring.config.bidder; + +import jakarta.validation.constraints.NotBlank; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.adverxo.AdverxoBidder; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.config.bidder.util.UsersyncerCreator; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/adverxo.yaml", factory = YamlPropertySourceFactory.class) +public class AdverxoBidderConfiguration { + + private static final String BIDDER_NAME = "adverxo"; + + @Bean("adverxoConfigurationProperties") + @ConfigurationProperties("adapters.adverxo") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps adverxoBidderDeps(BidderConfigurationProperties adverxoConfigurationProperties, + @NotBlank @Value("${external-url}") String externalUrl, + JacksonMapper mapper, CurrencyConversionService currencyConversionService) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(adverxoConfigurationProperties) + .usersyncerCreator(UsersyncerCreator.create(externalUrl)) + .bidderCreator(config -> new AdverxoBidder(config.getEndpoint(), mapper, currencyConversionService)) + .assemble(); + } +} diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml new file mode 100644 index 00000000000..c0d300ef27f --- /dev/null +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -0,0 +1,27 @@ +adapters: + adverxo: + endpoint: "https://pbsadverxo.com/auction?adUnitId={{adUnitId}}&auth={{auth}}" + endpoint-compression: gzip + meta-info: + maintainer-email: developer@adverxo.com + app-media-types: + - banner + - native + - video + site-media-types: + - banner + - native + - video + supported-vendors: + vendor-id: 0 + userSync: + cookie-family-name: adverxo + iframe: + url: https://pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + support-cors: false + userMacro: $UID + redirect: + url: https://pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + support-cors: false + userMacro: '$UID' + diff --git a/src/main/resources/static/bidder-params/adverxo.json b/src/main/resources/static/bidder-params/adverxo.json new file mode 100644 index 00000000000..072abe4df99 --- /dev/null +++ b/src/main/resources/static/bidder-params/adverxo.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Adverxo Adapter Params", + "description": "A schema which validates params accepted by the Adverxo adapter", + "type": "object", + "properties": { + "adUnitId": { + "type": "integer", + "minimum": 1, + "description": "Unique identifier for the ad unit in Adverxo platform." + }, + "auth": { + "type": "string", + "minLength": 6, + "description": "Authentication token provided by Adverxo platform for the AdUnit." + } + }, + "required": ["adUnitId", "auth"] +} diff --git a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java new file mode 100644 index 00000000000..e7a3ed7a87c --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.bidder.adverxo; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.VertxTest; +import org.prebid.server.currency.CurrencyConversionService; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +@ExtendWith(MockitoExtension.class) + +public class AdverxoBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://test.endpoint.com"; + + @Mock + private CurrencyConversionService currencyConversionService; + + private AdverxoBidder target; + + @BeforeEach + public void setUp() { + target = new AdverxoBidder(ENDPOINT_URL, jacksonMapper, currencyConversionService); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> new AdverxoBidder( + "invalid_url", + jacksonMapper, + currencyConversionService)); + } +} diff --git a/src/test/java/org/prebid/server/it/AdverxoTest.java b/src/test/java/org/prebid/server/it/AdverxoTest.java new file mode 100644 index 00000000000..f60a88afce4 --- /dev/null +++ b/src/test/java/org/prebid/server/it/AdverxoTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class AdverxoTest extends IntegrationTest{ + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromTheAdverxo() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adverxo-exchange")) + .withQueryParam("adUnitId", equalTo("1")) + .withQueryParam("auth", equalTo("123456")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/adverxo/test-adverxo-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/adverxo/test-adverxo-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/adverxo/test-auction-adverxo-request.json", + Endpoint.openrtb2_auction); + // then + System.out.println("Actual response: " + response.asString()); + assertJsonEquals("openrtb2/adverxo/test-auction-adverxo-response.json", response, + singletonList("adverxo")); + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json new file mode 100644 index 00000000000..714bb864fb4 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json @@ -0,0 +1,33 @@ +{ + "id": "test-bid-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "bidfloor": 1, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "page": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "127.0.0.1" + }, + "tmax": 500, + "test": 1 +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json new file mode 100644 index 00000000000..ba4153c1a0c --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json @@ -0,0 +1,21 @@ +{ + "id": "test-bid-response", + "cur": "USD", + "seatbid": [ + { + "seat": "adverxo", + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=${AUCTION_PRICE}", + "mtype": 1, + "w": 300, + "h": 250 + } + ] + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json new file mode 100644 index 00000000000..751d662a661 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json @@ -0,0 +1,33 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "bidder": { + "adverxo": { + "adUnitId": 1, + "auth": "123456" + } + } + } + } + } + ], + "site": { + "page": "http://testpage.com" + }, + "device": { + "ua": "Mozilla/5.0" + }, + "tmax": 1000 +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json new file mode 100644 index 00000000000..894592bd891 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json @@ -0,0 +1,21 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "adverxo", + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" +} diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 2e115d00348..423fcbc81be 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -45,6 +45,8 @@ adapters.adpone.enabled=true adapters.adpone.endpoint=http://localhost:8090/adpone-exchange adapters.adot.enabled=true adapters.adot.endpoint=http://localhost:8090/adot-exchange +adapters.adverxo.enabled=true +adapters.adverxo.endpoint=http://localhost:8090/adverxo-exchange?adUnitId={{adUnitId}}&auth={{auth}} adapters.adview.enabled=true adapters.adview.endpoint=http://localhost:8090/adview-exchange?accountId={{AccountId}} adapters.adprime.enabled=true From 50062ce667d93cdb8cfc119df964906171a124ef Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Tue, 28 Jan 2025 09:33:22 +0100 Subject: [PATCH 02/12] fix checkstyle --- .../spring/config/bidder/AdverxoBidderConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java index f1a66b21e4e..5387350af3d 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java @@ -1,7 +1,5 @@ package org.prebid.server.spring.config.bidder; -import jakarta.validation.constraints.NotBlank; - import org.prebid.server.bidder.BidderDeps; import org.prebid.server.bidder.adverxo.AdverxoBidder; import org.prebid.server.currency.CurrencyConversionService; @@ -16,6 +14,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import jakarta.validation.constraints.NotBlank; + @Configuration @PropertySource(value = "classpath:/bidder-config/adverxo.yaml", factory = YamlPropertySourceFactory.class) public class AdverxoBidderConfiguration { From 84a0490e00337d0ee7fd2b4a33fe2074de8e65af Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Tue, 28 Jan 2025 17:09:14 +0100 Subject: [PATCH 03/12] Fix tests --- .../bidder/adverxo/AdverxoBidderTest.java | 224 +++++++++++++++++- .../org/prebid/server/it/AdverxoTest.java | 3 +- .../adverxo/test-adverxo-bid-request.json | 32 ++- .../adverxo/test-adverxo-bid-response.json | 33 ++- .../adverxo/test-auction-adverxo-request.json | 17 +- .../test-auction-adverxo-response.json | 23 +- 6 files changed, 304 insertions(+), 28 deletions(-) diff --git a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java index e7a3ed7a87c..581c53f469f 100644 --- a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java @@ -1,20 +1,45 @@ package org.prebid.server.bidder.adverxo; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.adverxo.ExtImpAdverxo; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import java.math.BigDecimal; +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) - public class AdverxoBidderTest extends VertxTest { - private static final String ENDPOINT_URL = "https://test.endpoint.com"; + private static final String ENDPOINT_URL = "https://test.endpoint.com/{{adUnitId}}/{{auth}}"; + private static final String AD_UNIT_ID = "123"; + private static final String AUTH = "testAuth"; @Mock private CurrencyConversionService currencyConversionService; @@ -33,4 +58,199 @@ public void creationShouldFailOnInvalidEndpointUrl() { jacksonMapper, currencyConversionService)); } + + @Test + public void makeHttpRequestsShouldReturnErrorIfImpExtInvalid() { + // Given + final BidRequest bidRequest = givenBidRequest(impBuilder -> + impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) + ); + + // When + final Result>> result = target.makeHttpRequests(bidRequest); + + // Then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).startsWith("Error parsing ext.imp.bidder"); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldReplaceMacrosInEndpointUrl() { + // Given + final BidRequest bidRequest = givenBidRequest(identity()); + + // When + final Result>> result = target.makeHttpRequests(bidRequest); + + // Then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://test.endpoint.com/123/testAuth"); + } + + @Test + public void makeHttpRequestsShouldConvertCurrencyIfNeeded() { + // Given + final BigDecimal bidFloor = BigDecimal.ONE; + final String bidFloorCur = "EUR"; + final BigDecimal convertedPrice = BigDecimal.TEN; + + when(currencyConversionService.convertCurrency(any(), any(), any(), any())) + .thenReturn(convertedPrice); + + final BidRequest bidRequest = givenBidRequest(impBuilder -> + impBuilder + .bidfloor(bidFloor) + .bidfloorcur(bidFloorCur) + ); + + // When + final Result>> result = target.makeHttpRequests(bidRequest); + + // Then + verify(currencyConversionService).convertCurrency( + eq(bidFloor), + any(), + eq(bidFloorCur), + eq("USD") + ); + + final BidRequest outgoingRequest = result.getValue().get(0).getPayload(); + final Imp modifiedImp = outgoingRequest.getImp().get(0); + assertThat(modifiedImp.getBidfloor()).isEqualTo(convertedPrice); + assertThat(modifiedImp.getBidfloorcur()).isEqualTo("USD"); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // Given + final BidderCall httpCall = givenHttpCall(null, "invalid"); + + // When + final Result> result = target.makeBids(httpCall, null); + + // Then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).startsWith("Failed to decode"); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { + // Given + final BidderCall httpCall = givenHttpCall(null, + mapper.writeValueAsString(null)); + + // When + final Result> result = target.makeBids(httpCall, null); + + // Then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldCorrectlyResolveBidTypes() throws JsonProcessingException { + // Given + final BidResponse bidResponse = BidResponse.builder() + .cur("USD") + .seatbid(List.of(SeatBid.builder() + .bid(List.of( + Bid.builder().impid("123").mtype(1).adm("bannerAdm").build(), + Bid.builder().impid("456").mtype(2).adm("videoAdm").build(), + Bid.builder().impid("789").mtype(4).adm("{\"native\":{\"assets\":[]}}").build())) + .build())) + .build(); + + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), + mapper.writeValueAsString(bidResponse)); + + // When + final Result> result = target.makeBids(httpCall, null); + + // Then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.banner, BidType.video, BidType.xNative); + } + + @Test + public void makeBidsShouldReplacePriceMacroInAdmAndNurl() throws JsonProcessingException { + // Given + final Bid bid = Bid.builder() + .impid("123") + .mtype(1) + .adm("Price is ${AUCTION_PRICE}") + .nurl("nurl?price=${AUCTION_PRICE}") + .price(BigDecimal.valueOf(5.55)) + .build(); + + final BidResponse bidResponse = BidResponse.builder() + .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) + .build(); + + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), + mapper.writeValueAsString(bidResponse)); + + // When + final Result> result = target.makeBids(httpCall, null); + + // Then + final BidderBid bidderBid = result.getValue().get(0); + assertThat(bidderBid.getBid().getAdm()).isEqualTo("Price is 5.55"); + assertThat(bidderBid.getBid().getNurl()).isEqualTo("nurl?price=5.55"); + } + + @Test + public void makeBidsShouldHandleNativeAdmParsing() throws JsonProcessingException { + // Given + final String adm = "{\"native\": {\"key\": \"value\"}}"; + final Bid bid = Bid.builder() + .impid("123") + .mtype(4) + .adm(adm) + .build(); + + final BidResponse bidResponse = BidResponse.builder() + .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) + .build(); + + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), + mapper.writeValueAsString(bidResponse)); + + // When + final Result> result = target.makeBids(httpCall, null); + + // Then + assertThat(result.getValue().get(0).getBid().getAdm()).isEqualTo("{\"key\":\"value\"}"); + } + + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { + return givenBidRequest(identity(), impCustomizer); + } + + private static BidRequest givenBidRequest( + UnaryOperator bidRequestCustomizer, + UnaryOperator impCustomizer) { + + return bidRequestCustomizer.apply(BidRequest.builder() + .imp(List.of(impCustomizer.apply(Imp.builder() + .id("123") + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpAdverxo.of( + Integer.parseInt(AD_UNIT_ID), AUTH))))) + .build()))) + .build(); + } + + private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, body), + null); + } } diff --git a/src/test/java/org/prebid/server/it/AdverxoTest.java b/src/test/java/org/prebid/server/it/AdverxoTest.java index f60a88afce4..52835f7f0e5 100644 --- a/src/test/java/org/prebid/server/it/AdverxoTest.java +++ b/src/test/java/org/prebid/server/it/AdverxoTest.java @@ -22,14 +22,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromTheAdverxo() throws IOExcept WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adverxo-exchange")) .withQueryParam("adUnitId", equalTo("1")) .withQueryParam("auth", equalTo("123456")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/adverxo/test-adverxo-bid-request.json"))) + .withRequestBody(equalToJson(jsonFrom("openrtb2/adverxo/test-adverxo-bid-request.json"), true, true)) .willReturn(aResponse().withBody(jsonFrom("openrtb2/adverxo/test-adverxo-bid-response.json")))); // when final Response response = responseFor("openrtb2/adverxo/test-auction-adverxo-request.json", Endpoint.openrtb2_auction); // then - System.out.println("Actual response: " + response.asString()); assertJsonEquals("openrtb2/adverxo/test-auction-adverxo-response.json", response, singletonList("adverxo")); } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json index 714bb864fb4..b1a0a5c0c8b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-request.json @@ -1,5 +1,5 @@ { - "id": "test-bid-request", + "id": "test-auction-request", "imp": [ { "id": "imp1", @@ -11,9 +11,9 @@ } ] }, - "bidfloor": 1, - "bidfloorcur": "USD", + "secure": 1, "ext": { + "tid": "${json-unit.any-string}", "bidder": { "adUnitId": 1, "auth": "123456" @@ -22,12 +22,30 @@ } ], "site": { - "page": "http://example.com" + "domain": "testpage.com", + "page": "http://testpage.com", + "publisher": { + "domain": "testpage.com" + }, + "ext": { + "amp": 0 + } }, "device": { "ua": "Mozilla/5.0", - "ip": "127.0.0.1" + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, - "tmax": 500, - "test": 1 + "regs": { + "ext": { + "gdpr": 0 + } + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json index ba4153c1a0c..0d282ff107d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-adverxo-bid-response.json @@ -1,21 +1,40 @@ { - "id": "test-bid-response", - "cur": "USD", + "id": "test-auction-request", "seatbid": [ { "seat": "adverxo", + "group": 0, "bid": [ { "id": "bid1", "impid": "imp1", "price": 1.23, - "adm": "", - "nurl": "https://example.com/win?price=${AUCTION_PRICE}", - "mtype": 1, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", "w": 300, - "h": 250 + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } } ] } - ] + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adverxo": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json index 751d662a661..c89d2013fd5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-request.json @@ -12,13 +12,9 @@ ] }, "ext": { - "prebid": { - "bidder": { - "adverxo": { - "adUnitId": 1, - "auth": "123456" - } - } + "adverxo": { + "adUnitId": 1, + "auth": "123456" } } } @@ -29,5 +25,10 @@ "device": { "ua": "Mozilla/5.0" }, - "tmax": 1000 + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json index 894592bd891..0d282ff107d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adverxo/test-auction-adverxo-response.json @@ -3,6 +3,7 @@ "seatbid": [ { "seat": "adverxo", + "group": 0, "bid": [ { "id": "bid1", @@ -10,12 +11,30 @@ "price": 1.23, "adm": "", "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", "w": 300, "h": 250, - "mtype": 1 + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } } ] } ], - "cur": "USD" + "cur": "USD", + "ext": { + "responsetimemillis": { + "adverxo": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } } From 61c230f066b8debc21d091970ed4f5e3dd4df30f Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Tue, 28 Jan 2025 17:13:05 +0100 Subject: [PATCH 04/12] fix clean code --- src/test/java/org/prebid/server/it/AdverxoTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/prebid/server/it/AdverxoTest.java b/src/test/java/org/prebid/server/it/AdverxoTest.java index 52835f7f0e5..30b2f3bc049 100644 --- a/src/test/java/org/prebid/server/it/AdverxoTest.java +++ b/src/test/java/org/prebid/server/it/AdverxoTest.java @@ -14,7 +14,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static java.util.Collections.singletonList; -public class AdverxoTest extends IntegrationTest{ +public class AdverxoTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromTheAdverxo() throws IOException, JSONException { @@ -28,6 +28,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromTheAdverxo() throws IOExcept // when final Response response = responseFor("openrtb2/adverxo/test-auction-adverxo-request.json", Endpoint.openrtb2_auction); + // then assertJsonEquals("openrtb2/adverxo/test-auction-adverxo-response.json", response, singletonList("adverxo")); From 2be2f839a271c6eb374d0e00e005f790ee41c1d9 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Thu, 13 Feb 2025 17:34:54 +0100 Subject: [PATCH 05/12] fix comments --- .../server/bidder/adverxo/AdverxoBidder.java | 129 ++++++------- .../ext/request/adverxo/ExtImpAdverxo.java | 2 +- src/main/resources/bidder-config/adverxo.yaml | 4 +- .../bidder/adverxo/AdverxoBidderTest.java | 182 ++++++++++++++---- 4 files changed, 203 insertions(+), 114 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java index 3dd43e2b077..128bd3f5d2d 100644 --- a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -8,15 +8,14 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; -import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Price; import org.prebid.server.bidder.model.Result; import org.prebid.server.currency.CurrencyConversionService; import org.prebid.server.exception.PreBidException; @@ -25,14 +24,16 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.adverxo.ExtImpAdverxo; import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; +import java.util.stream.Collectors; public class AdverxoBidder implements Bidder { @@ -64,10 +65,10 @@ public Result>> makeHttpRequests(BidRequest request try { final ExtImpAdverxo extImp = parseImpExt(imp); final String endpoint = resolveEndpoint(extImp); - final Imp modifiedImp = modifyImp(imp, request); + final Imp modifiedImp = modifyImp(request, imp); final BidRequest outgoingRequest = createRequest(request, modifiedImp); - requests.add(createHttpRequest(outgoingRequest, endpoint, imp.getId())); + requests.add(createHttpRequest(outgoingRequest, endpoint)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } @@ -84,108 +85,91 @@ private ExtImpAdverxo parseImpExt(Imp imp) { } } - private String resolveEndpoint(ExtImpAdverxo extImpAdverxo) { - final String adUnitAsString = Optional.of(extImpAdverxo.getAdUnitId()) - .map(Object::toString) - .orElse(StringUtils.EMPTY); - final String authAsString = Optional.ofNullable(extImpAdverxo.getAuth()) - .map(Object::toString) - .orElse(StringUtils.EMPTY); - + private String resolveEndpoint(ExtImpAdverxo extImp) { return endpointUrl - .replace(ADUNIT_MACROS_ENDPOINT, adUnitAsString) - .replace(AUTH_MACROS_ENDPOINT, authAsString); + .replace(ADUNIT_MACROS_ENDPOINT, + extImp.getAdUnitId() == null ? StringUtils.EMPTY : String.valueOf(extImp.getAdUnitId())) + .replace(AUTH_MACROS_ENDPOINT, HttpUtil.encodeUrl(StringUtils.defaultString(extImp.getAuth()))); } - private Imp modifyImp(Imp imp, BidRequest request) { - final BigDecimal bidFloor = imp.getBidfloor(); - final String bidFloorCur = imp.getBidfloorcur(); + private Imp modifyImp(BidRequest bidRequest, Imp imp) { + final Price resolvedBidFloor = resolveBidFloor(imp, bidRequest); - if (bidFloor != null && bidFloor.compareTo(BigDecimal.ZERO) > 0 - && StringUtils.isNotBlank(bidFloorCur) - && !StringUtils.equalsIgnoreCase(bidFloorCur, DEFAULT_BID_CURRENCY)) { + return imp.toBuilder() + .bidfloor(resolvedBidFloor.getValue()) + .bidfloorcur(resolvedBidFloor.getCurrency()) + .build(); + } - final BigDecimal convertedPrice = currencyConversionService.convertCurrency( - bidFloor, - request, - bidFloorCur, - DEFAULT_BID_CURRENCY - ); + private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { + final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, DEFAULT_BID_CURRENCY) + ? convertBidFloor(initialBidFloorPrice, bidRequest) + : initialBidFloorPrice; + } - return imp.toBuilder() - .bidfloor(convertedPrice) - .bidfloorcur(DEFAULT_BID_CURRENCY) - .build(); - } - return imp; + private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { + final BigDecimal convertedPrice = currencyConversionService.convertCurrency( + bidFloorPrice.getValue(), + bidRequest, + bidFloorPrice.getCurrency(), + DEFAULT_BID_CURRENCY); + + return Price.of(DEFAULT_BID_CURRENCY, convertedPrice); } - private BidRequest createRequest(BidRequest originalRequest, Imp modifiedImp) { + private static BidRequest createRequest(BidRequest originalRequest, Imp modifiedImp) { return originalRequest.toBuilder() .imp(Collections.singletonList(modifiedImp)) .build(); } - private HttpRequest createHttpRequest(BidRequest outgoingRequest, - String endpoint, - String impId) { - return HttpRequest.builder() - .method(HttpMethod.POST) - .uri(endpoint) - .headers(HttpUtil.headers()) - .body(mapper.encodeToBytes(outgoingRequest)) - .impIds(Collections.singleton(impId)) - .payload(outgoingRequest) - .build(); + private HttpRequest createHttpRequest(BidRequest outgoingRequest, String endpoint) { + return BidderUtil.defaultRequest(outgoingRequest, endpoint, mapper); } @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { - final List bidderErrors = new ArrayList<>(); final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - return Result.withValues(extractBids(bidResponse, bidderErrors)); + return Result.withValues(extractBids(bidResponse)); } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } - private List extractBids(BidResponse bidResponse, - List bidderErrors) { + private List extractBids(BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } - final String currency = bidResponse.getCur(); - final List bidderBids = new ArrayList<>(); - - for (SeatBid seatBid : bidResponse.getSeatbid()) { - if (CollectionUtils.isEmpty(seatBid.getBid())) { - continue; - } + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> makeBid(bid, bidResponse.getCur())) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } - for (Bid bid : seatBid.getBid()) { - final BidType bidType = getBidType(bid); - final String resolvedAdm = resolveAdmForBidType(bid, bidType); - final Bid processedBid = processBidMacros(bid, resolvedAdm); + private BidderBid makeBid(Bid bid, String currency) { + final BidType bidType = getBidType(bid.getMtype()); + final String resolvedAdm = resolveAdmForBidType(bid, bidType); + final Bid processedBid = processBidMacros(bid, resolvedAdm); - bidderBids.add(BidderBid.of(processedBid, bidType, currency)); - } - } - - return bidderBids; + return BidderBid.of(processedBid, bidType, currency); } - private BidType getBidType(Bid bid) { - final Integer markupType = ObjectUtils.defaultIfNull(bid.getMtype(), 0); - - return switch (markupType) { + private static BidType getBidType(Integer mType) { + return switch (mType) { case 1 -> BidType.banner; case 2 -> BidType.video; case 4 -> BidType.xNative; - default -> throw new PreBidException( - "could not define media type for impression: " + bid.getImpid()); + case null, default -> + throw new PreBidException("Unsupported mType " + mType); }; } @@ -203,12 +187,11 @@ private String resolveAdmForBidType(Bid bid, BidType bidType) { } } - private Bid processBidMacros(Bid bid, String adm) { + private static Bid processBidMacros(Bid bid, String adm) { final String price = bid.getPrice() != null ? bid.getPrice().toPlainString() : "0"; return bid.toBuilder() .adm(replaceMacro(adm, price)) - .nurl(replaceMacro(bid.getNurl(), price)) .build(); } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java index e634e7b2b1a..a2f028b2a6f 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java @@ -9,7 +9,7 @@ public class ExtImpAdverxo { @JsonProperty("adUnitId") - int adUnitId; + Integer adUnitId; @JsonProperty("auth") String auth; } diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index c0d300ef27f..49c25857156 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -1,6 +1,6 @@ adapters: adverxo: - endpoint: "https://pbsadverxo.com/auction?adUnitId={{adUnitId}}&auth={{auth}}" + endpoint: https://pbsadverxo.com/auction?adUnitId={{adUnitId}}&auth={{auth}} endpoint-compression: gzip meta-info: maintainer-email: developer@adverxo.com @@ -19,7 +19,7 @@ adapters: iframe: url: https://pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} support-cors: false - userMacro: $UID + userMacro: '$UID' redirect: url: https://pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} support-cors: false diff --git a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java index 581c53f469f..ef05b163090 100644 --- a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java @@ -61,15 +61,15 @@ public void creationShouldFailOnInvalidEndpointUrl() { @Test public void makeHttpRequestsShouldReturnErrorIfImpExtInvalid() { - // Given + // given final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) ); - // When + // when final Result>> result = target.makeHttpRequests(bidRequest); - // Then + // then assertThat(result.getErrors()).hasSize(1); assertThat(result.getErrors().get(0).getMessage()).startsWith("Error parsing ext.imp.bidder"); assertThat(result.getValue()).isEmpty(); @@ -77,13 +77,13 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtInvalid() { @Test public void makeHttpRequestsShouldReplaceMacrosInEndpointUrl() { - // Given + // given final BidRequest bidRequest = givenBidRequest(identity()); - // When + // when final Result>> result = target.makeHttpRequests(bidRequest); - // Then + // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) @@ -92,7 +92,7 @@ public void makeHttpRequestsShouldReplaceMacrosInEndpointUrl() { @Test public void makeHttpRequestsShouldConvertCurrencyIfNeeded() { - // Given + // given final BigDecimal bidFloor = BigDecimal.ONE; final String bidFloorCur = "EUR"; final BigDecimal convertedPrice = BigDecimal.TEN; @@ -106,10 +106,10 @@ public void makeHttpRequestsShouldConvertCurrencyIfNeeded() { .bidfloorcur(bidFloorCur) ); - // When + // when final Result>> result = target.makeHttpRequests(bidRequest); - // Then + // then verify(currencyConversionService).convertCurrency( eq(bidFloor), any(), @@ -123,68 +123,133 @@ public void makeHttpRequestsShouldConvertCurrencyIfNeeded() { assertThat(modifiedImp.getBidfloorcur()).isEqualTo("USD"); } + @Test + public void makeHttpRequestsShouldCreateMultipleRequestsForMultipleImps() { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(List.of( + givenImp("imp1"), + givenImp("imp2"), + givenImp("imp3") + )) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(3); + } + @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { - // Given + // given final BidderCall httpCall = givenHttpCall(null, "invalid"); - // When + // when final Result> result = target.makeBids(httpCall, null); - // Then + // then assertThat(result.getErrors()).hasSize(1); assertThat(result.getErrors().get(0).getMessage()).startsWith("Failed to decode"); } @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { - // Given + // given final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); - // When + // when final Result> result = target.makeBids(httpCall, null); - // Then + // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).isEmpty(); } @Test - public void makeBidsShouldCorrectlyResolveBidTypes() throws JsonProcessingException { - // Given + public void makeBidsShouldResolveBannerBidType() throws JsonProcessingException { + // given + final BidResponse bidResponse = givenBidResponse( + Bid.builder().impid("123").mtype(1).adm("bannerAdm").build()); + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.banner); + } + + @Test + public void makeBidsShouldResolveVideoBidType() throws JsonProcessingException { + // given + final BidResponse bidResponse = givenBidResponse( + Bid.builder().impid("456").mtype(2).adm("videoAdm").build()); + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.video); + } + + @Test + public void makeBidsShouldResolveNativeBidType() throws JsonProcessingException { + // given + final BidResponse bidResponse = givenBidResponse( + Bid.builder().impid("789").mtype(4).adm("{\"native\":{\"assets\":[]}}").build()); + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.xNative); + } + + @Test + public void makeBidsShouldReturnErrorWhenMTypeIsUnsupported() throws JsonProcessingException { + // given + final Bid bid = Bid.builder() + .impid("999") + .mtype(99) + .adm("unsupportedAdm") + .build(); + final BidResponse bidResponse = BidResponse.builder() - .cur("USD") - .seatbid(List.of(SeatBid.builder() - .bid(List.of( - Bid.builder().impid("123").mtype(1).adm("bannerAdm").build(), - Bid.builder().impid("456").mtype(2).adm("videoAdm").build(), - Bid.builder().impid("789").mtype(4).adm("{\"native\":{\"assets\":[]}}").build())) - .build())) + .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) .build(); final BidderCall httpCall = givenHttpCall( BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); - // When + // when final Result> result = target.makeBids(httpCall, null); - // Then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .extracting(BidderBid::getType) - .containsExactly(BidType.banner, BidType.video, BidType.xNative); + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).contains("Unsupported mType 99"); + assertThat(result.getValue()).isEmpty(); } @Test public void makeBidsShouldReplacePriceMacroInAdmAndNurl() throws JsonProcessingException { - // Given + // given final Bid bid = Bid.builder() .impid("123") .mtype(1) .adm("Price is ${AUCTION_PRICE}") - .nurl("nurl?price=${AUCTION_PRICE}") .price(BigDecimal.valueOf(5.55)) .build(); @@ -196,18 +261,17 @@ public void makeBidsShouldReplacePriceMacroInAdmAndNurl() throws JsonProcessingE BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); - // When + // when final Result> result = target.makeBids(httpCall, null); - // Then + // then final BidderBid bidderBid = result.getValue().get(0); assertThat(bidderBid.getBid().getAdm()).isEqualTo("Price is 5.55"); - assertThat(bidderBid.getBid().getNurl()).isEqualTo("nurl?price=5.55"); } @Test public void makeBidsShouldHandleNativeAdmParsing() throws JsonProcessingException { - // Given + // given final String adm = "{\"native\": {\"key\": \"value\"}}"; final Bid bid = Bid.builder() .impid("123") @@ -223,13 +287,40 @@ public void makeBidsShouldHandleNativeAdmParsing() throws JsonProcessingExceptio BidRequest.builder().build(), mapper.writeValueAsString(bidResponse)); - // When + // when final Result> result = target.makeBids(httpCall, null); - // Then + // then assertThat(result.getValue().get(0).getBid().getAdm()).isEqualTo("{\"key\":\"value\"}"); } + @Test + public void makeBidsShouldReturnErrorWhenNativeAdmIsInvalid() throws JsonProcessingException { + // given + final String invalidAdm = "{invalid_json"; + final Bid bid = Bid.builder() + .impid("123") + .mtype(4) + .adm(invalidAdm) + .build(); + + final BidResponse bidResponse = BidResponse.builder() + .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) + .build(); + + final BidderCall httpCall = givenHttpCall( + BidRequest.builder().build(), + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).contains("Error parsing native ADM"); + assertThat(result.getValue()).isEmpty(); + } + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { return givenBidRequest(identity(), impCustomizer); } @@ -253,4 +344,19 @@ private static BidderCall givenHttpCall(BidRequest bidRequest, Strin HttpResponse.of(200, null, body), null); } + + private static Imp givenImp(String impId) { + return Imp.builder() + .id(impId) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpAdverxo.of(123, "testAuth")))) + .build(); + } + + private static BidResponse givenBidResponse(Bid bid) { + return BidResponse.builder() + .cur("USD") + .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) + .build(); + } + } From a333369f584f301e5bc367cae058c90755a01dfe Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Fri, 14 Feb 2025 15:04:04 +0100 Subject: [PATCH 06/12] fix comments --- .../server/bidder/adverxo/AdverxoBidder.java | 10 ++---- src/main/resources/bidder-config/adverxo.yaml | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java index 128bd3f5d2d..3e9acf1664a 100644 --- a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -68,7 +68,7 @@ public Result>> makeHttpRequests(BidRequest request final Imp modifiedImp = modifyImp(request, imp); final BidRequest outgoingRequest = createRequest(request, modifiedImp); - requests.add(createHttpRequest(outgoingRequest, endpoint)); + requests.add(BidderUtil.defaultRequest(outgoingRequest, endpoint, mapper)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } @@ -124,10 +124,6 @@ private static BidRequest createRequest(BidRequest originalRequest, Imp modified .build(); } - private HttpRequest createHttpRequest(BidRequest outgoingRequest, String endpoint) { - return BidderUtil.defaultRequest(outgoingRequest, endpoint, mapper); - } - @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { @@ -151,7 +147,6 @@ private List extractBids(BidResponse bidResponse) { .flatMap(Collection::stream) .filter(Objects::nonNull) .map(bid -> makeBid(bid, bidResponse.getCur())) - .filter(Objects::nonNull) .collect(Collectors.toList()); } @@ -168,8 +163,7 @@ private static BidType getBidType(Integer mType) { case 1 -> BidType.banner; case 2 -> BidType.video; case 4 -> BidType.xNative; - case null, default -> - throw new PreBidException("Unsupported mType " + mType); + case null, default -> throw new PreBidException("Unsupported mType " + mType); }; } diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index 49c25857156..6bcac288352 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -2,6 +2,37 @@ adapters: adverxo: endpoint: https://pbsadverxo.com/auction?adUnitId={{adUnitId}}&auth={{auth}} endpoint-compression: gzip + aliases: + adport: + enabled: false + endpoint: https://adport.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + userSync: + iframe: + url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' + redirect: + url: https://adport.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' + bidsmind: + enabled: false + endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + userSync: + iframe: + url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' + redirect: + url: https://bidsmind.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' + mobupps: + enabled: false + endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + userSync: + iframe: + url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' + redirect: + url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} + userMacro: '[UID]' meta-info: maintainer-email: developer@adverxo.com app-media-types: From 37ee752953de7c3bd9ad7476da8eb2ed0811d1c8 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 19 Feb 2025 16:05:09 +0100 Subject: [PATCH 07/12] fix comments --- src/main/resources/bidder-config/adverxo.yaml | 30 +++++++---- .../java/org/prebid/server/it/AdportTest.java | 36 +++++++++++++ .../org/prebid/server/it/BidsmindTest.java | 36 +++++++++++++ .../org/prebid/server/it/MobuppsTest.java | 36 +++++++++++++ .../adport/test-adport-bid-request.json | 51 +++++++++++++++++++ .../adport/test-adport-bid-response.json | 40 +++++++++++++++ .../adport/test-auction-adport-request.json | 34 +++++++++++++ .../adport/test-auction-adport-response.json | 40 +++++++++++++++ .../test-auction-bidsmind-request.json | 34 +++++++++++++ .../test-auction-bidsmind-response.json | 40 +++++++++++++++ .../bidsmind/test-bidsmind-bid-request.json | 51 +++++++++++++++++++ .../bidsmind/test-bidsmind-bid-response.json | 40 +++++++++++++++ .../mobupps/test-auction-mobupps-request.json | 34 +++++++++++++ .../test-auction-mobupps-response.json | 40 +++++++++++++++ .../mobupps/test-mobupps-bid-request.json | 51 +++++++++++++++++++ .../mobupps/test-mobupps-bid-response.json | 40 +++++++++++++++ .../server/it/test-application.properties | 6 +++ 17 files changed, 630 insertions(+), 9 deletions(-) create mode 100644 src/test/java/org/prebid/server/it/AdportTest.java create mode 100644 src/test/java/org/prebid/server/it/BidsmindTest.java create mode 100644 src/test/java/org/prebid/server/it/MobuppsTest.java create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index 6bcac288352..217f61da4e3 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -5,34 +5,46 @@ adapters: aliases: adport: enabled: false - endpoint: https://adport.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + endpoint: https://adport.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} userSync: + enabled: true + cookie-family-name: adverxo iframe: url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false redirect: url: https://adport.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false bidsmind: enabled: false - endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} userSync: + enabled: true + cookie-family-name: adverxo iframe: url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false redirect: url: https://bidsmind.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false mobupps: enabled: false - endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnit}}&auth={{auth}} + endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} userSync: + enabled: true + cookie-family-name: adverxo iframe: url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false redirect: url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '[UID]' + userMacro: '$UID' + support-cors: false meta-info: maintainer-email: developer@adverxo.com app-media-types: diff --git a/src/test/java/org/prebid/server/it/AdportTest.java b/src/test/java/org/prebid/server/it/AdportTest.java new file mode 100644 index 00000000000..8b07fa08cde --- /dev/null +++ b/src/test/java/org/prebid/server/it/AdportTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class AdportTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromTheAdport() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adport-exchange")) + .withQueryParam("adUnitId", equalTo("1")) + .withQueryParam("auth", equalTo("123456")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/adport/test-adport-bid-request.json"), true, true)) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/adport/test-adport-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/adport/test-auction-adport-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/adport/test-auction-adport-response.json", response, + singletonList("adport")); + } +} diff --git a/src/test/java/org/prebid/server/it/BidsmindTest.java b/src/test/java/org/prebid/server/it/BidsmindTest.java new file mode 100644 index 00000000000..84c73dc44d1 --- /dev/null +++ b/src/test/java/org/prebid/server/it/BidsmindTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class BidsmindTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromTheBidsmind() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/bidsmind-exchange")) + .withQueryParam("adUnitId", equalTo("1")) + .withQueryParam("auth", equalTo("123456")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/bidsmind/test-bidsmind-bid-request.json"), true, true)) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/bidsmind/test-bidsmind-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/bidsmind/test-auction-bidsmind-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/bidsmind/test-auction-bidsmind-response.json", response, + singletonList("bidsmind")); + } +} diff --git a/src/test/java/org/prebid/server/it/MobuppsTest.java b/src/test/java/org/prebid/server/it/MobuppsTest.java new file mode 100644 index 00000000000..016f0f614d3 --- /dev/null +++ b/src/test/java/org/prebid/server/it/MobuppsTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class MobuppsTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromTheMobupps() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/mobupps-exchange")) + .withQueryParam("adUnitId", equalTo("1")) + .withQueryParam("auth", equalTo("123456")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/mobupps/test-mobupps-bid-request.json"), true, true)) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/mobupps/test-mobupps-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/mobupps/test-auction-mobupps-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/mobupps/test-auction-mobupps-response.json", response, + singletonList("mobupps")); + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-request.json new file mode 100644 index 00000000000..b1a0a5c0c8b --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-request.json @@ -0,0 +1,51 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "domain": "testpage.com", + "page": "http://testpage.com", + "publisher": { + "domain": "testpage.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-response.json new file mode 100644 index 00000000000..f4914655cb9 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-adport-bid-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "adport", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adport": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-request.json new file mode 100644 index 00000000000..9839e0dbb16 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-request.json @@ -0,0 +1,34 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "adport": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "page": "http://testpage.com" + }, + "device": { + "ua": "Mozilla/5.0" + }, + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-response.json new file mode 100644 index 00000000000..f4914655cb9 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adport/test-auction-adport-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "adport", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adport": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-request.json new file mode 100644 index 00000000000..ce24d044803 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-request.json @@ -0,0 +1,34 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidsmind": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "page": "http://testpage.com" + }, + "device": { + "ua": "Mozilla/5.0" + }, + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-response.json new file mode 100644 index 00000000000..86ea73d0bba --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-auction-bidsmind-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "bidsmind", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "bidsmind": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-request.json new file mode 100644 index 00000000000..b1a0a5c0c8b --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-request.json @@ -0,0 +1,51 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "domain": "testpage.com", + "page": "http://testpage.com", + "publisher": { + "domain": "testpage.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-response.json new file mode 100644 index 00000000000..86ea73d0bba --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidsmind/test-bidsmind-bid-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "bidsmind", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "bidsmind": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json new file mode 100644 index 00000000000..13f73b2a640 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json @@ -0,0 +1,34 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "mobupps": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "page": "http://testpage.com" + }, + "device": { + "ua": "Mozilla/5.0" + }, + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json new file mode 100644 index 00000000000..735fcd2ee33 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "mobupps", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "mobupps": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json new file mode 100644 index 00000000000..b1a0a5c0c8b --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json @@ -0,0 +1,51 @@ +{ + "id": "test-auction-request", + "imp": [ + { + "id": "imp1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "adUnitId": 1, + "auth": "123456" + } + } + } + ], + "site": { + "domain": "testpage.com", + "page": "http://testpage.com", + "publisher": { + "domain": "testpage.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json new file mode 100644 index 00000000000..735fcd2ee33 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json @@ -0,0 +1,40 @@ +{ + "id": "test-auction-request", + "seatbid": [ + { + "seat": "mobupps", + "group": 0, + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "nurl": "https://example.com/win?price=1.23", + "crid": "creative1", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "origbidcpm": 1.23, + "origbidcur": "USD", + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "mobupps": 0 + }, + "tmaxrequest": 5000, + "prebid": { + "auctiontimestamp": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 423fcbc81be..932a58c054f 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -47,6 +47,12 @@ adapters.adot.enabled=true adapters.adot.endpoint=http://localhost:8090/adot-exchange adapters.adverxo.enabled=true adapters.adverxo.endpoint=http://localhost:8090/adverxo-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.adport.enabled=true +adapters.adverxo.aliases.adport.endpoint=http://localhost:8090/adport-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.bidsmind.enabled=true +adapters.adverxo.aliases.bidsmind.endpoint=http://localhost:8090/bidsmind-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.mobupps.enabled=true +adapters.adverxo.aliases.mobupps.endpoint=http://localhost:8090/mobupps-exchange?adUnitId={{adUnitId}}&auth={{auth}} adapters.adview.enabled=true adapters.adview.endpoint=http://localhost:8090/adview-exchange?accountId={{AccountId}} adapters.adprime.enabled=true From c21a5aae255d21be6d995714dcf4fa108db6c1fe Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 19 Feb 2025 16:19:25 +0100 Subject: [PATCH 08/12] removing params in integration tests --- src/test/java/org/prebid/server/it/AdportTest.java | 3 --- src/test/java/org/prebid/server/it/BidsmindTest.java | 3 --- src/test/java/org/prebid/server/it/MobuppsTest.java | 3 --- .../org/prebid/server/it/test-application.properties | 6 +++--- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/prebid/server/it/AdportTest.java b/src/test/java/org/prebid/server/it/AdportTest.java index 8b07fa08cde..c78e1309fbb 100644 --- a/src/test/java/org/prebid/server/it/AdportTest.java +++ b/src/test/java/org/prebid/server/it/AdportTest.java @@ -8,7 +8,6 @@ import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; @@ -20,8 +19,6 @@ public class AdportTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromTheAdport() throws IOException, JSONException { // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adport-exchange")) - .withQueryParam("adUnitId", equalTo("1")) - .withQueryParam("auth", equalTo("123456")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adport/test-adport-bid-request.json"), true, true)) .willReturn(aResponse().withBody(jsonFrom("openrtb2/adport/test-adport-bid-response.json")))); diff --git a/src/test/java/org/prebid/server/it/BidsmindTest.java b/src/test/java/org/prebid/server/it/BidsmindTest.java index 84c73dc44d1..e834092d229 100644 --- a/src/test/java/org/prebid/server/it/BidsmindTest.java +++ b/src/test/java/org/prebid/server/it/BidsmindTest.java @@ -8,7 +8,6 @@ import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; @@ -20,8 +19,6 @@ public class BidsmindTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromTheBidsmind() throws IOException, JSONException { // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/bidsmind-exchange")) - .withQueryParam("adUnitId", equalTo("1")) - .withQueryParam("auth", equalTo("123456")) .withRequestBody(equalToJson(jsonFrom("openrtb2/bidsmind/test-bidsmind-bid-request.json"), true, true)) .willReturn(aResponse().withBody(jsonFrom("openrtb2/bidsmind/test-bidsmind-bid-response.json")))); diff --git a/src/test/java/org/prebid/server/it/MobuppsTest.java b/src/test/java/org/prebid/server/it/MobuppsTest.java index 016f0f614d3..9987de46469 100644 --- a/src/test/java/org/prebid/server/it/MobuppsTest.java +++ b/src/test/java/org/prebid/server/it/MobuppsTest.java @@ -8,7 +8,6 @@ import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; @@ -20,8 +19,6 @@ public class MobuppsTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromTheMobupps() throws IOException, JSONException { // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/mobupps-exchange")) - .withQueryParam("adUnitId", equalTo("1")) - .withQueryParam("auth", equalTo("123456")) .withRequestBody(equalToJson(jsonFrom("openrtb2/mobupps/test-mobupps-bid-request.json"), true, true)) .willReturn(aResponse().withBody(jsonFrom("openrtb2/mobupps/test-mobupps-bid-response.json")))); diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 932a58c054f..68e3602a6dc 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -48,11 +48,11 @@ adapters.adot.endpoint=http://localhost:8090/adot-exchange adapters.adverxo.enabled=true adapters.adverxo.endpoint=http://localhost:8090/adverxo-exchange?adUnitId={{adUnitId}}&auth={{auth}} adapters.adverxo.aliases.adport.enabled=true -adapters.adverxo.aliases.adport.endpoint=http://localhost:8090/adport-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.adport.endpoint=http://localhost:8090/adport-exchange adapters.adverxo.aliases.bidsmind.enabled=true -adapters.adverxo.aliases.bidsmind.endpoint=http://localhost:8090/bidsmind-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.bidsmind.endpoint=http://localhost:8090/bidsmind-exchange adapters.adverxo.aliases.mobupps.enabled=true -adapters.adverxo.aliases.mobupps.endpoint=http://localhost:8090/mobupps-exchange?adUnitId={{adUnitId}}&auth={{auth}} +adapters.adverxo.aliases.mobupps.endpoint=http://localhost:8090/mobupps-exchange adapters.adview.enabled=true adapters.adview.endpoint=http://localhost:8090/adview-exchange?accountId={{AccountId}} adapters.adprime.enabled=true From 86b00f3fdba7b12c24945bd6ff3182097f966446 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Thu, 20 Feb 2025 12:19:53 +0100 Subject: [PATCH 09/12] fix comments --- src/main/resources/bidder-config/adverxo.yaml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index 217f61da4e3..a18090627c9 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -6,44 +6,44 @@ adapters: adport: enabled: false endpoint: https://adport.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} - userSync: + usersync: enabled: true - cookie-family-name: adverxo + cookie-family-name: adport iframe: url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false redirect: url: https://adport.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false bidsmind: enabled: false endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} - userSync: + usersync: enabled: true - cookie-family-name: adverxo + cookie-family-name: bidsmind iframe: url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false redirect: url: https://bidsmind.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false mobupps: enabled: false endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} - userSync: + usersync: enabled: true - cookie-family-name: adverxo + cookie-family-name: mobupps iframe: url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false redirect: url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} - userMacro: '$UID' + uid-macro: '$UID' support-cors: false meta-info: maintainer-email: developer@adverxo.com @@ -57,14 +57,14 @@ adapters: - video supported-vendors: vendor-id: 0 - userSync: + usersync: cookie-family-name: adverxo iframe: url: https://pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} support-cors: false - userMacro: '$UID' + uid-macro: '$UID' redirect: url: https://pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} support-cors: false - userMacro: '$UID' + uid-macro: '$UID' From 97c61ec149091212a181a18aa8f5c4bf90e502f3 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 5 Mar 2025 10:15:02 +0100 Subject: [PATCH 10/12] fix comments --- .../server/bidder/adverxo/AdverxoBidder.java | 27 ++++---------- .../ext/request/adverxo/ExtImpAdverxo.java | 1 - .../bidder/AdverxoBidderConfiguration.java | 3 +- src/main/resources/bidder-config/adverxo.yaml | 6 ++-- .../bidder/adverxo/AdverxoBidderTest.java | 35 ++----------------- 5 files changed, 15 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java index 3e9acf1664a..e3b1a142d39 100644 --- a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -1,8 +1,6 @@ package org.prebid.server.bidder.adverxo; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.Bid; @@ -86,9 +84,9 @@ private ExtImpAdverxo parseImpExt(Imp imp) { } private String resolveEndpoint(ExtImpAdverxo extImp) { + final String adUnitId = String.valueOf(extImp.getAdUnitId()); return endpointUrl - .replace(ADUNIT_MACROS_ENDPOINT, - extImp.getAdUnitId() == null ? StringUtils.EMPTY : String.valueOf(extImp.getAdUnitId())) + .replace(ADUNIT_MACROS_ENDPOINT, adUnitId == null ? "0" : adUnitId) .replace(AUTH_MACROS_ENDPOINT, HttpUtil.encodeUrl(StringUtils.defaultString(extImp.getAuth()))); } @@ -135,7 +133,6 @@ public Result> makeBids(BidderCall httpCall, BidRequ } private List extractBids(BidResponse bidResponse) { - if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } @@ -152,7 +149,7 @@ private List extractBids(BidResponse bidResponse) { private BidderBid makeBid(Bid bid, String currency) { final BidType bidType = getBidType(bid.getMtype()); - final String resolvedAdm = resolveAdmForBidType(bid, bidType); + final String resolvedAdm = bidType == BidType.xNative ? resolveAdm(bid.getAdm(), bid.getPrice()) : bid.getAdm(); final Bid processedBid = processBidMacros(bid, resolvedAdm); return BidderBid.of(processedBid, bidType, currency); @@ -167,20 +164,6 @@ private static BidType getBidType(Integer mType) { }; } - private String resolveAdmForBidType(Bid bid, BidType bidType) { - if (bidType != BidType.xNative) { - return bid.getAdm(); - } - - try { - final JsonNode admNode = mapper.mapper().readTree(bid.getAdm()); - final JsonNode nativeNode = admNode.get("native"); - return nativeNode != null ? nativeNode.toString() : bid.getAdm(); - } catch (JsonProcessingException e) { - throw new PreBidException("Error parsing native ADM: " + e.getMessage()); - } - } - private static Bid processBidMacros(Bid bid, String adm) { final String price = bid.getPrice() != null ? bid.getPrice().toPlainString() : "0"; @@ -192,4 +175,8 @@ private static Bid processBidMacros(Bid bid, String adm) { private static String replaceMacro(String input, String value) { return input != null ? input.replace(PRICE_MACRO, value) : null; } + + private static String resolveAdm(String bidAdm, BigDecimal price) { + return StringUtils.isNotBlank(bidAdm) ? bidAdm.replace("${AUCTION_PRICE}", String.valueOf(price)) : bidAdm; + } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java index a2f028b2a6f..908dadba21f 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java @@ -10,6 +10,5 @@ public class ExtImpAdverxo { @JsonProperty("adUnitId") Integer adUnitId; - @JsonProperty("auth") String auth; } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java index 5387350af3d..ae9224670b7 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/AdverxoBidderConfiguration.java @@ -31,7 +31,8 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps adverxoBidderDeps(BidderConfigurationProperties adverxoConfigurationProperties, @NotBlank @Value("${external-url}") String externalUrl, - JacksonMapper mapper, CurrencyConversionService currencyConversionService) { + JacksonMapper mapper, + CurrencyConversionService currencyConversionService) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(adverxoConfigurationProperties) diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index a18090627c9..8474c269505 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -7,7 +7,7 @@ adapters: enabled: false endpoint: https://adport.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} usersync: - enabled: true + enabled: false cookie-family-name: adport iframe: url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} @@ -21,7 +21,7 @@ adapters: enabled: false endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} usersync: - enabled: true + enabled: false cookie-family-name: bidsmind iframe: url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} @@ -35,7 +35,7 @@ adapters: enabled: false endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}} usersync: - enabled: true + enabled: false cookie-family-name: mobupps iframe: url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}} diff --git a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java index ef05b163090..986b8e9134b 100644 --- a/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adverxo/AdverxoBidderTest.java @@ -63,8 +63,7 @@ public void creationShouldFailOnInvalidEndpointUrl() { public void makeHttpRequestsShouldReturnErrorIfImpExtInvalid() { // given final BidRequest bidRequest = givenBidRequest(impBuilder -> - impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) - ); + impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -103,8 +102,7 @@ public void makeHttpRequestsShouldConvertCurrencyIfNeeded() { final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder .bidfloor(bidFloor) - .bidfloorcur(bidFloorCur) - ); + .bidfloorcur(bidFloorCur)); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -291,34 +289,7 @@ public void makeBidsShouldHandleNativeAdmParsing() throws JsonProcessingExceptio final Result> result = target.makeBids(httpCall, null); // then - assertThat(result.getValue().get(0).getBid().getAdm()).isEqualTo("{\"key\":\"value\"}"); - } - - @Test - public void makeBidsShouldReturnErrorWhenNativeAdmIsInvalid() throws JsonProcessingException { - // given - final String invalidAdm = "{invalid_json"; - final Bid bid = Bid.builder() - .impid("123") - .mtype(4) - .adm(invalidAdm) - .build(); - - final BidResponse bidResponse = BidResponse.builder() - .seatbid(List.of(SeatBid.builder().bid(List.of(bid)).build())) - .build(); - - final BidderCall httpCall = givenHttpCall( - BidRequest.builder().build(), - mapper.writeValueAsString(bidResponse)); - - // when - final Result> result = target.makeBids(httpCall, null); - - // then - assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).contains("Error parsing native ADM"); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getValue().get(0).getBid().getAdm()).isEqualTo(adm); } private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { From aab6750f1c37b8d5e028b2584c0e317b78c02550 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 12 Mar 2025 14:06:44 +0100 Subject: [PATCH 11/12] fix comments --- .../java/org/prebid/server/bidder/adverxo/AdverxoBidder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java index e3b1a142d39..ede0b4c51c6 100644 --- a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -84,9 +84,8 @@ private ExtImpAdverxo parseImpExt(Imp imp) { } private String resolveEndpoint(ExtImpAdverxo extImp) { - final String adUnitId = String.valueOf(extImp.getAdUnitId()); return endpointUrl - .replace(ADUNIT_MACROS_ENDPOINT, adUnitId == null ? "0" : adUnitId) + .replace(ADUNIT_MACROS_ENDPOINT, Objects.toString(extImp.getAdUnitId(), "0")) .replace(AUTH_MACROS_ENDPOINT, HttpUtil.encodeUrl(StringUtils.defaultString(extImp.getAuth()))); } From 6f0427d730952df09c73d4f77cabed8ac8eac946 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Fri, 14 Mar 2025 11:49:10 +0100 Subject: [PATCH 12/12] fix comments --- .../java/org/prebid/server/bidder/adverxo/AdverxoBidder.java | 4 +++- .../proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java index ede0b4c51c6..1880a2e9ad4 100644 --- a/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java +++ b/src/main/java/org/prebid/server/bidder/adverxo/AdverxoBidder.java @@ -47,8 +47,10 @@ public class AdverxoBidder implements Bidder { private final JacksonMapper mapper; private final CurrencyConversionService currencyConversionService; - public AdverxoBidder(String endpointUrl, JacksonMapper mapper, + public AdverxoBidder(String endpointUrl, + JacksonMapper mapper, CurrencyConversionService currencyConversionService) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.mapper = mapper; this.currencyConversionService = currencyConversionService; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java index 908dadba21f..86a90653464 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adverxo/ExtImpAdverxo.java @@ -1,14 +1,13 @@ package org.prebid.server.proto.openrtb.ext.request.adverxo; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; import lombok.Value; -@Value -@AllArgsConstructor(staticName = "of") +@Value(staticConstructor = "of") public class ExtImpAdverxo { @JsonProperty("adUnitId") Integer adUnitId; + String auth; }