diff --git a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java index f2228778feb..8d45320cb9c 100644 --- a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java +++ b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java @@ -94,6 +94,110 @@ public Result>> makeHttpRequests(BidRequest bidRequ return Result.withValue(BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper)); } + private ExtImpRtbhouse parseImpExt(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), RTBHOUSE_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + } + + private Price resolveBidFloor(Imp imp, ExtImpRtbhouse impExt, BidRequest bidRequest) { + final List brCur = bidRequest.getCur(); + final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + + final BigDecimal impExtBidFloor = impExt.getBidFloor(); + final String impExtCurrency = impExtBidFloor != null && brCur != null && !brCur.isEmpty() + ? brCur.getFirst() : null; + final Price impExtBidFloorPrice = Price.of(impExtCurrency, impExtBidFloor); + final Price resolvedPrice = initialBidFloorPrice.getValue() == null + ? impExtBidFloorPrice : initialBidFloorPrice; + + return BidderUtil.isValidPrice(resolvedPrice) + && !StringUtils.equalsIgnoreCase(resolvedPrice.getCurrency(), BIDDER_CURRENCY) + ? convertBidFloor(resolvedPrice, imp.getId(), bidRequest) + : resolvedPrice; + } + + private Price convertBidFloor(Price bidFloorPrice, String impId, BidRequest bidRequest) { + final String bidFloorCur = bidFloorPrice.getCurrency(); + try { + final BigDecimal convertedPrice = currencyConversionService + .convertCurrency(bidFloorPrice.getValue(), bidRequest, bidFloorCur, BIDDER_CURRENCY); + + return Price.of(BIDDER_CURRENCY, convertedPrice); + } catch (PreBidException e) { + throw new PreBidException(String.format( + "Unable to convert provided bid floor currency from %s to %s for imp `%s`", + bidFloorCur, BIDDER_CURRENCY, impId)); + } + } + + private static Imp modifyImp(Imp imp, Price bidFloorPrice) { + return imp.toBuilder() + .tagid(extractTagId(imp)) + .bidfloorcur(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getCurrency)) + .bidfloor(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getValue)) + .pmp(null) + .build(); + } + + private static String extractTagId(Imp imp) { + return Optional.ofNullable(imp.getTagid()) + .filter(StringUtils::isNotBlank) + .or(() -> extractGpid(imp)) + .or(() -> extractAdslot(imp)) + .or(() -> extractPbadslot(imp)) + .or(() -> Optional.ofNullable(imp.getId()) + .filter(StringUtils::isNotBlank)) + .orElse(null); + } + + private static Optional extractGpid(Imp imp) { + return Optional.ofNullable(imp.getExt()) + .map(ext -> ext.get("gpid")) + .map(JsonNode::textValue) + .filter(StringUtils::isNotBlank); + } + + private static Optional extractAdslot(Imp imp) { + return Optional.ofNullable(imp.getExt()) + .map(ext -> ext.get("data")) + .map(data -> data.get("adserver")) + .map(adserver -> adserver.get("adslot")) + .map(JsonNode::textValue) + .filter(StringUtils::isNotBlank); + } + + private static Optional extractPbadslot(Imp imp) { + return Optional.ofNullable(imp.getExt()) + .map(ext -> ext.get("data")) + .map(data -> data.get("pbadslot")) + .map(JsonNode::textValue) + .filter(StringUtils::isNotBlank); + } + + private Site modifySite(Site site, String publisherId) { + final ObjectNode prebidNode = mapper.mapper().createObjectNode(); + prebidNode.put("publisherId", publisherId); + + final ExtPublisher extPublisher = ExtPublisher.empty(); + extPublisher.addProperty("prebid", prebidNode); + + final Publisher publisher = Optional.ofNullable(site) + .map(Site::getPublisher) + .map(Publisher::toBuilder) + .orElseGet(Publisher::builder) + .ext(extPublisher) + .build(); + + return Optional.ofNullable(site) + .map(Site::toBuilder) + .orElseGet(Site::builder) + .publisher(publisher) + .build(); + } + @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { @@ -144,23 +248,6 @@ private BidderBid resolveBidderBid(Bid bid, .build(); } - private String resolveNativeAdm(String adm, List bidderErrors) { - final JsonNode admNode; - try { - admNode = mapper.mapper().readTree(adm); - } catch (JsonProcessingException e) { - bidderErrors.add(BidderError.badServerResponse("Unable to parse native adm: %s".formatted(adm))); - return null; - } - - final JsonNode nativeNode = admNode.get("native"); - if (nativeNode != null) { - return nativeNode.toString(); - } - - return adm; - } - private static BidType getBidType(String impId, List imps) { for (Imp imp : imps) { if (imp.getId().equals(impId)) { @@ -176,51 +263,21 @@ private static BidType getBidType(String impId, List imps) { return BidType.banner; } - private ExtImpRtbhouse parseImpExt(Imp imp) { + private String resolveNativeAdm(String adm, List bidderErrors) { + final JsonNode admNode; try { - return mapper.mapper().convertValue(imp.getExt(), RTBHOUSE_EXT_TYPE_REFERENCE).getBidder(); - } catch (IllegalArgumentException e) { - throw new PreBidException(e.getMessage()); + admNode = mapper.mapper().readTree(adm); + } catch (JsonProcessingException e) { + bidderErrors.add(BidderError.badServerResponse("Unable to parse native adm: %s".formatted(adm))); + return null; } - } - private static Imp modifyImp(Imp imp, Price bidFloorPrice) { - return imp.toBuilder() - .bidfloorcur(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getCurrency)) - .bidfloor(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getValue)) - .pmp(null) - .build(); - } - - private Price resolveBidFloor(Imp imp, ExtImpRtbhouse impExt, BidRequest bidRequest) { - final List brCur = bidRequest.getCur(); - final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); - - final BigDecimal impExtBidFloor = impExt.getBidFloor(); - final String impExtCurrency = impExtBidFloor != null && brCur != null && !brCur.isEmpty() - ? brCur.getFirst() : null; - final Price impExtBidFloorPrice = Price.of(impExtCurrency, impExtBidFloor); - final Price resolvedPrice = initialBidFloorPrice.getValue() == null - ? impExtBidFloorPrice : initialBidFloorPrice; - - return BidderUtil.isValidPrice(resolvedPrice) - && !StringUtils.equalsIgnoreCase(resolvedPrice.getCurrency(), BIDDER_CURRENCY) - ? convertBidFloor(resolvedPrice, imp.getId(), bidRequest) - : resolvedPrice; - } - - private Price convertBidFloor(Price bidFloorPrice, String impId, BidRequest bidRequest) { - final String bidFloorCur = bidFloorPrice.getCurrency(); - try { - final BigDecimal convertedPrice = currencyConversionService - .convertCurrency(bidFloorPrice.getValue(), bidRequest, bidFloorCur, BIDDER_CURRENCY); - - return Price.of(BIDDER_CURRENCY, convertedPrice); - } catch (PreBidException e) { - throw new PreBidException(String.format( - "Unable to convert provided bid floor currency from %s to %s for imp `%s`", - bidFloorCur, BIDDER_CURRENCY, impId)); + final JsonNode nativeNode = admNode.get("native"); + if (nativeNode != null) { + return nativeNode.toString(); } + + return adm; } private static Bid resolveMacros(Bid bid) { @@ -232,25 +289,4 @@ private static Bid resolveMacros(Bid bid) { .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } - - private Site modifySite(Site site, String publisherId) { - final ObjectNode prebidNode = mapper.mapper().createObjectNode(); - prebidNode.put("publisherId", publisherId); - - final ExtPublisher extPublisher = ExtPublisher.empty(); - extPublisher.addProperty("prebid", prebidNode); - - final Publisher publisher = Optional.ofNullable(site) - .map(Site::getPublisher) - .map(Publisher::toBuilder) - .orElseGet(Publisher::builder) - .ext(extPublisher) - .build(); - - return Optional.ofNullable(site) - .map(Site::toBuilder) - .orElseGet(Site::builder) - .publisher(publisher) - .build(); - } } diff --git a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java index fe10dad45e3..7a4e483303c 100644 --- a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java @@ -34,7 +34,9 @@ import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.function.Function; +import java.util.function.UnaryOperator; import static java.util.Collections.singletonList; import static java.util.function.Function.identity; @@ -70,96 +72,6 @@ public void creationShouldFailOnInvalidEndpointUrl() { jacksonMapper)); } - @Test - public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { - // given - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); - final BidderCall httpCall = givenHttpCall(bidRequest, "invalid"); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().getFirst().getMessage()).startsWith("Failed to decode: Unrecognized token"); - assertThat(result.getErrors().getFirst().getType()).isEqualTo(BidderError.Type.bad_server_response); - assertThat(result.getValue()).isEmpty(); - } - - @Test - public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { - // given - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); - final BidderCall httpCall = givenHttpCall(bidRequest, - mapper.writeValueAsString(null)); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); - } - - @Test - public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { - // given - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); - final BidderCall httpCall = givenHttpCall(bidRequest, - mapper.writeValueAsString(BidResponse.builder().build())); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); - } - - @Test - public void makeBidsShouldReturnBannerBidIfBannerIsPresent() throws JsonProcessingException { - // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").build())) - .build(); - final BidderCall httpCall = givenHttpCall( - bidRequest, - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), banner, "USD")); - } - - @Test - public void makeBidsShouldReturnVideoBidIfVideoIsPresent() throws JsonProcessingException { - // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .video(Video.builder().build()) - .build())) - .build(); - - final BidderCall httpCall = givenHttpCall( - bidRequest, - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(Bid.builder().impid("123").build(), video, "USD")); - } - @Test public void makeHttpRequestsShouldConvertCurrencyIfRequestCurrencyDoesNotMatchBidderCurrency() { // given @@ -276,56 +188,6 @@ public void makeHttpRequestsShouldNotReturnErrorIfNativePresent() { assertThat(result.getValue()).hasSize(1); } - @Test - public void makeBidsShouldParseNativeAdmData() throws JsonProcessingException { - // given - final BidRequest bidRequest = givenBidRequest( - impBuilder -> impBuilder.id("123") - .banner(null) - .xNative(Native.builder().build())); - final ObjectNode admNode = mapper.createObjectNode(); - final ObjectNode nativeNode = mapper.createObjectNode(); - nativeNode.put("property1", "value1"); - admNode.set("native", nativeNode); - final BidderCall httpCall = givenHttpCall(bidRequest, - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123") - .adm(admNode.toString())))); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - - assertThat(result.getValue()) - .extracting(BidderBid::getBid) - .extracting(Bid::getAdm) - .containsExactly("{\"property1\":\"value1\"}"); - } - - @Test - public void makeBidsShouldReturnBidWithResolvedMacros() throws JsonProcessingException { - // given - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); - final BidderCall httpCall = givenHttpCall(null, - mapper.writeValueAsString(givenBidResponse( - bidBuilder -> bidBuilder - .nurl("nurl:${AUCTION_PRICE}") - .adm("adm:${AUCTION_PRICE}") - .price(BigDecimal.valueOf(12.34))))); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsExactly(tuple("nurl:12.34", "adm:12.34")); - } - @Test public void makeHttpRequestsShouldCreateSiteAndPublisherWhenBidRequestHasNoSite() { // given @@ -518,6 +380,273 @@ public void makeHttpRequestsShouldAlwaysRemovePmpField() { .containsOnlyNulls(); } + @Test + public void makeHttpRequestsShouldSetTagidFromGpid() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("imp123").ext(givenRtbhouseExt(node -> node.put("gpid", "gpid_value"))), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsExactly("gpid_value"); + } + + @Test + public void makeHttpRequestsShouldSetTagidFromAdserverAdslot() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("imp123") + .ext(givenRtbhouseExt(node -> + node.set("data", mapper.valueToTree( + Map.of("adserver", Map.of("adslot", "adslot_value")))))), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsExactly("adslot_value"); + } + + @Test + public void makeHttpRequestsShouldSetTagidFromPbadslot() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("imp123") + .ext(givenRtbhouseExt(node -> + node.set("data", mapper.valueToTree(Map.of("pbadslot", "pbadslot_value"))))), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsExactly("pbadslot_value"); + } + + @Test + public void makeHttpRequestsShouldSetTagidFromImpIdWhenNoOtherFields() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("imp123"), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsExactly("imp123"); + } + + @Test + public void makeHttpRequestsShouldSetTagidToNullWhenNoFieldsAvailable() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id(null), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsOnlyNulls(); + } + + @Test + public void makeHttpRequestsShouldPreserveExistingTagid() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("imp123") + .tagid("existing_tagid") + .ext(givenRtbhouseExt(node -> node.put("gpid", "gpid_value"))), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getTagid) + .containsExactly("existing_tagid"); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); + final BidderCall httpCall = givenHttpCall(bidRequest, "invalid"); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().getFirst().getMessage()).startsWith("Failed to decode: Unrecognized token"); + assertThat(result.getErrors().getFirst().getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); + final BidderCall httpCall = givenHttpCall(bidRequest, + mapper.writeValueAsString(null)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); + final BidderCall httpCall = givenHttpCall(bidRequest, + mapper.writeValueAsString(BidResponse.builder().build())); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnBannerBidIfBannerIsPresent() throws JsonProcessingException { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").build())) + .build(); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), banner, "USD")); + } + + @Test + public void makeBidsShouldReturnVideoBidIfVideoIsPresent() throws JsonProcessingException { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .video(Video.builder().build()) + .build())) + .build(); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .containsExactly(BidderBid.of(Bid.builder().impid("123").build(), video, "USD")); + } + + @Test + public void makeBidsShouldParseNativeAdmData() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.id("123") + .banner(null) + .xNative(Native.builder().build())); + final ObjectNode admNode = mapper.createObjectNode(); + final ObjectNode nativeNode = mapper.createObjectNode(); + nativeNode.put("property1", "value1"); + admNode.set("native", nativeNode); + final BidderCall httpCall = givenHttpCall(bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123") + .adm(admNode.toString())))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .containsExactly("{\"property1\":\"value1\"}"); + } + + @Test + public void makeBidsShouldReturnBidWithResolvedMacros() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(null)); + final BidderCall httpCall = givenHttpCall(null, + mapper.writeValueAsString(givenBidResponse( + bidBuilder -> bidBuilder + .nurl("nurl:${AUCTION_PRICE}") + .adm("adm:${AUCTION_PRICE}") + .price(BigDecimal.valueOf(12.34))))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getNurl, Bid::getAdm) + .containsExactly(tuple("nurl:12.34", "adm:12.34")); + } + private static BidResponse givenBidResponse(Function bidCustomizer) { return BidResponse.builder() .cur("USD") @@ -562,4 +691,12 @@ private static Imp givenImp(Function impCustomiz .build())))) .build(); } + + private static ObjectNode givenRtbhouseExt(UnaryOperator extCustomizer) { + final ObjectNode extNode = mapper.valueToTree(ExtPrebid.of(null, ExtImpRtbhouse.builder() + .publisherId("publisherId") + .region("region") + .build())); + return extCustomizer.apply(extNode); + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json index e63afde3937..28d0438942f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json @@ -13,7 +13,8 @@ "bidder": { "publisherId": "publisherId" } - } + }, + "tagid": "imp_id" } ], "source": {