From a9ccd6d09d018927ffda2e2746e1f293934020cf Mon Sep 17 00:00:00 2001 From: Oleksandr Zhevedenko <720803+Net-burst@users.noreply.github.com> Date: Mon, 4 Nov 2024 22:21:40 -0500 Subject: [PATCH 1/3] Make OpenRTB battr logic more strict --- .../ortb2/blocking/core/RequestUpdater.java | 33 ++--- .../blocking/core/RequestUpdaterTest.java | 118 +++++++++++++++++- 2 files changed, 136 insertions(+), 15 deletions(-) diff --git a/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java b/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java index ac963b94857..78744e7c07f 100644 --- a/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java +++ b/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; public class RequestUpdater { @@ -99,13 +98,15 @@ private static List extractBattr(Map btype, List battr) { - final List existingBtype = banner != null ? banner.getBtype() : null; - final List existingBattr = banner != null ? banner.getBattr() : null; + if (banner == null) { + return null; + } + + final List existingBtype = banner.getBtype(); + final List existingBattr = banner.getBattr(); return CollectionUtils.isEmpty(existingBtype) || CollectionUtils.isEmpty(existingBattr) - ? Optional.ofNullable(banner) - .map(Banner::toBuilder) - .orElseGet(Banner::builder) + ? banner.toBuilder() .btype(CollectionUtils.isNotEmpty(existingBtype) ? existingBtype : btype) .battr(CollectionUtils.isNotEmpty(existingBattr) ? existingBattr : battr) .build() @@ -113,22 +114,26 @@ private static Banner updateBanner(Banner banner, List btype, List battr) { - final List existingBattr = video != null ? video.getBattr() : null; + if (video == null) { + return null; + } + + final List existingBattr = video.getBattr(); return CollectionUtils.isEmpty(existingBattr) - ? Optional.ofNullable(video) - .map(Video::toBuilder) - .orElseGet(Video::builder) + ? video.toBuilder() .battr(battr) .build() : video; } private static Audio updateAudio(Audio audio, List battr) { - final List existingBattr = audio != null ? audio.getBattr() : null; + if (audio == null) { + return null; + } + + final List existingBattr = audio.getBattr(); return CollectionUtils.isEmpty(existingBattr) - ? Optional.ofNullable(audio) - .map(Audio::toBuilder) - .orElseGet(Audio::builder) + ? audio.toBuilder() .battr(battr) .build() : audio; diff --git a/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java b/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java index 630c09e96d1..1f03f82edb1 100644 --- a/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java +++ b/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java @@ -354,7 +354,12 @@ MediaType.VIDEO, singletonMap("impId1", asList(3, 4)), MediaType.AUDIO, singletonMap("impId1", asList(5, 6)))) .build()); final BidRequest request = BidRequest.builder() - .imp(singletonList(Imp.builder().id("impId1").build())) + .imp(singletonList(Imp.builder() + .id("impId1") + .banner(Banner.builder().build()) + .video(Video.builder().build()) + .audio(Audio.builder().build()) + .build())) .build(); // when and then @@ -373,4 +378,115 @@ MediaType.AUDIO, singletonMap("impId1", asList(5, 6)))) .build())) .build()); } + + @Test + public void shouldNotUpdateMissingBanner() { + // given + final RequestUpdater updater = RequestUpdater.create( + BlockedAttributes.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .btype(singletonMap("impId1", asList(1, 2))) + .battr(Map.of( + MediaType.BANNER, singletonMap("impId1", asList(1, 2)), + MediaType.VIDEO, singletonMap("impId1", asList(3, 4)), + MediaType.AUDIO, singletonMap("impId1", asList(5, 6)))) + .build()); + final BidRequest request = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("impId1") + .video(Video.builder().build()) + .audio(Audio.builder().build()) + .build())) + .build(); + + // when and then + assertThat(updater.update(request)).isEqualTo(BidRequest.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .imp(singletonList(Imp.builder() + .id("impId1") + .video(Video.builder().battr(asList(3, 4)).build()) + .audio(Audio.builder().battr(asList(5, 6)).build()) + .build())) + .build()); + } + + @Test + public void shouldNotUpdateMissingVideo() { + // given + final RequestUpdater updater = RequestUpdater.create( + BlockedAttributes.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .btype(singletonMap("impId1", asList(1, 2))) + .battr(Map.of( + MediaType.BANNER, singletonMap("impId1", asList(1, 2)), + MediaType.VIDEO, singletonMap("impId1", asList(3, 4)), + MediaType.AUDIO, singletonMap("impId1", asList(5, 6)))) + .build()); + final BidRequest request = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("impId1") + .banner(Banner.builder().build()) + .audio(Audio.builder().build()) + .build())) + .build(); + + // when and then + assertThat(updater.update(request)).isEqualTo(BidRequest.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .imp(singletonList(Imp.builder() + .id("impId1") + .banner(Banner.builder() + .btype(asList(1, 2)) + .battr(asList(1, 2)) + .build()) + .audio(Audio.builder().battr(asList(5, 6)).build()) + .build())) + .build()); + } + + @Test + public void shouldNotUpdateMissingAudio() { + // given + final RequestUpdater updater = RequestUpdater.create( + BlockedAttributes.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .btype(singletonMap("impId1", asList(1, 2))) + .battr(Map.of( + MediaType.BANNER, singletonMap("impId1", asList(1, 2)), + MediaType.VIDEO, singletonMap("impId1", asList(3, 4)), + MediaType.AUDIO, singletonMap("impId1", asList(5, 6)))) + .build()); + final BidRequest request = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("impId1") + .banner(Banner.builder().build()) + .video(Video.builder().build()) + .build())) + .build(); + + // when and then + assertThat(updater.update(request)).isEqualTo(BidRequest.builder() + .badv(asList("domain1.com", "domain2.com")) + .bcat(asList("cat1", "cat2")) + .bapp(asList("app1", "app2")) + .imp(singletonList(Imp.builder() + .id("impId1") + .banner(Banner.builder() + .btype(asList(1, 2)) + .battr(asList(1, 2)) + .build()) + .video(Video.builder().battr(asList(3, 4)).build()) + .build())) + .build()); + } } From 7aa33f836b7443698852c92bca29bafc59b9f09c Mon Sep 17 00:00:00 2001 From: Oleksandr Zhevedenko <720803+Net-burst@users.noreply.github.com> Date: Tue, 5 Nov 2024 22:25:08 -0500 Subject: [PATCH 2/3] Make OpenRTB blocking module AccountConfigReader reflect only return result for present media types --- .../blocking/core/AccountConfigReader.java | 24 +++++----- .../core/AccountConfigReaderTest.java | 44 +++++++++---------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java b/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java index a7ee0425135..47b3e3204c7 100644 --- a/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java +++ b/extra/modules/ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java @@ -104,13 +104,13 @@ public Result blockedAttributesFor(BidRequest bidRequest) { final Result> bapp = blockedAttribute(BAPP_FIELD, String.class, BLOCKED_APP_FIELD, requestMediaTypes); final Result>> btype = - blockedAttributesForImps(BTYPE_FIELD, Integer.class, BLOCKED_BANNER_TYPE_FIELD, bidRequest); + blockedAttributesForImps(BTYPE_FIELD, Integer.class, BLOCKED_BANNER_TYPE_FIELD, BANNER_MEDIA_TYPE, bidRequest); final Result>> bannerBattr = - blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_BANNER_ATTR_FIELD, bidRequest); + blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_BANNER_ATTR_FIELD, BANNER_MEDIA_TYPE, bidRequest); final Result>> videoBattr = - blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_VIDEO_ATTR_FIELD, bidRequest); + blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_VIDEO_ATTR_FIELD, VIDEO_MEDIA_TYPE, bidRequest); final Result>> audioBattr = - blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_AUDIO_ATTR_FIELD, bidRequest); + blockedAttributesForImps(BATTR_FIELD, Integer.class, BLOCKED_AUDIO_ATTR_FIELD, AUDIO_MEDIA_TYPE, bidRequest); final Result>>> battr = mergeBlockedAttributes(bannerBattr, videoBattr, audioBattr); @@ -226,19 +226,23 @@ private Integer blockedCattaxComplementFromConfig() { private Result>> blockedAttributesForImps(String attribute, Class attributeType, String fieldName, + String attributeMediaType, BidRequest bidRequest) { final Map> attributeValues = new HashMap<>(); final List> results = new ArrayList<>(); for (final Imp imp : bidRequest.getImp()) { - final Result> attributeForImp = blockedAttribute( - attribute, attributeType, fieldName, mediaTypesFrom(imp)); - - if (attributeForImp.hasValue()) { - attributeValues.put(imp.getId(), attributeForImp.getValue()); + final Set actualMediaTypes = mediaTypesFrom(imp); + if (actualMediaTypes.contains(attributeMediaType)) { + final Result> attributeForImp = blockedAttribute( + attribute, attributeType, fieldName, actualMediaTypes); + + if (attributeForImp.hasValue()) { + attributeValues.put(imp.getId(), attributeForImp.getValue()); + } + results.add(attributeForImp); } - results.add(attributeForImp); } return Result.of( diff --git a/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReaderTest.java b/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReaderTest.java index f6568663807..e20bf2c3dac 100644 --- a/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReaderTest.java +++ b/extra/modules/ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReaderTest.java @@ -400,7 +400,7 @@ public void blockedAttributesForShouldReturnErrorWhenBlockedBannerTypeIsNotInteg final AccountConfigReader reader = AccountConfigReader.create(accountConfig, "bidder1", ORTB_VERSION, true); // when and then - assertThatThrownBy(() -> reader.blockedAttributesFor(emptyRequest())) + assertThatThrownBy(() -> reader.blockedAttributesFor(request(imp -> imp.banner(Banner.builder().build())))) .isInstanceOf(InvalidAccountConfigurationException.class) .hasMessage("blocked-banner-type field in account configuration has unexpected type. " + "Expected class java.lang.Integer"); @@ -700,17 +700,23 @@ public void blockedAttributesForShouldReturnResultWithBtypeAndWarningsFromOverri .btype(Attribute.btypeBuilder() .actionOverrides(AttributeActionOverrides.blocked(asList( ArrayOverride.of( - Conditions.of(singletonList("bidder1"), singletonList("video")), + Conditions.of(singletonList("bidder1"), singletonList("banner")), singletonList(1)), ArrayOverride.of( - Conditions.of(singletonList("bidder1"), singletonList("video")), + Conditions.of(singletonList("bidder1"), singletonList("banner")), singletonList(2)), ArrayOverride.of( - Conditions.of(singletonList("bidder1"), singletonList("banner")), + Conditions.of(singletonList("bidder1"), singletonList("video")), singletonList(3)), ArrayOverride.of( - Conditions.of(singletonList("bidder1"), singletonList("banner")), - singletonList(4))))) + Conditions.of(singletonList("bidder1"), singletonList("video")), + singletonList(4)), + ArrayOverride.of( + Conditions.of(singletonList("bidder1"), singletonList("audio")), + singletonList(5)), + ArrayOverride.of( + Conditions.of(singletonList("bidder1"), singletonList("audio")), + singletonList(6))))) .build()) .build())); final AccountConfigReader reader = AccountConfigReader.create(accountConfig, "bidder1", ORTB_VERSION, true); @@ -718,20 +724,16 @@ public void blockedAttributesForShouldReturnResultWithBtypeAndWarningsFromOverri // when and then final Map> expectedBtype = new HashMap<>(); expectedBtype.put("impId1", singletonList(1)); - expectedBtype.put("impId2", singletonList(3)); assertThat(reader .blockedAttributesFor(BidRequest.builder() .imp(asList( - Imp.builder().id("impId1").video(Video.builder().build()).build(), - Imp.builder().id("impId2").banner(Banner.builder().build()).build())) + Imp.builder().id("impId1").banner(Banner.builder().build()).build(), + Imp.builder().id("impId2").video(Video.builder().build()).build())) .build())) .isEqualTo(Result.of( BlockedAttributes.builder().btype(expectedBtype).build(), - asList( - "More than one conditions matches request. Bidder: bidder1, " + - "request media types: [video]", - "More than one conditions matches request. Bidder: bidder1, " + - "request media types: [banner]"))); + List.of("More than one conditions matches request. Bidder: bidder1, " + + "request media types: [banner]"))); } @Test @@ -778,8 +780,8 @@ public void blockedAttributesForShouldReturnResultWithAllAttributesForBanner() { final AccountConfigReader reader = AccountConfigReader.create(accountConfig, "bidder1", ORTB_VERSION, true); // when and then - assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1")))).isEqualTo( - Result.withValue(BlockedAttributes.builder() + assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1").banner(Banner.builder().build())))) + .isEqualTo(Result.withValue(BlockedAttributes.builder() .badv(singletonList("domain3.com")) .bcat(singletonList("cat3")) .bapp(singletonList("app3")) @@ -832,12 +834,11 @@ public void blockedAttributesForShouldReturnResultWithAllAttributesForVideo() { final AccountConfigReader reader = AccountConfigReader.create(accountConfig, "bidder1", ORTB_VERSION, true); // when and then - assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1")))).isEqualTo( - Result.withValue(BlockedAttributes.builder() + assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1").video(Video.builder().build())))) + .isEqualTo(Result.withValue(BlockedAttributes.builder() .badv(singletonList("domain3.com")) .bcat(singletonList("cat3")) .bapp(singletonList("app3")) - .btype(singletonMap("impId1", singletonList(3))) .battr(singletonMap(MediaType.VIDEO, singletonMap("impId1", singletonList(3)))) .build())); } @@ -886,12 +887,11 @@ public void blockedAttributesForShouldReturnResultWithAllAttributesForAudio() { final AccountConfigReader reader = AccountConfigReader.create(accountConfig, "bidder1", ORTB_VERSION, true); // when and then - assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1")))).isEqualTo( - Result.withValue(BlockedAttributes.builder() + assertThat(reader.blockedAttributesFor(request(imp -> imp.id("impId1").audio(Audio.builder().build())))) + .isEqualTo(Result.withValue(BlockedAttributes.builder() .badv(singletonList("domain3.com")) .bcat(singletonList("cat3")) .bapp(singletonList("app3")) - .btype(singletonMap("impId1", singletonList(3))) .battr(singletonMap(MediaType.AUDIO, singletonMap("impId1", singletonList(3)))) .build())); } From 765a0ba7732250792018d496c8ecc988e400ded8 Mon Sep 17 00:00:00 2001 From: osulzhenko <125548596+osulzhenko@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:13:21 +0200 Subject: [PATCH 3/3] Tests: Functional tests for OpenRTB battr strict logic (#3523) Add functional tests for OpenRTB battr strict logic --- .../ortb2blocking/Ortb2BlockingSpec.groovy | 135 +++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/ortb2blocking/Ortb2BlockingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/ortb2blocking/Ortb2BlockingSpec.groovy index b37cae6a067..bb644508090 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/ortb2blocking/Ortb2BlockingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/ortb2blocking/Ortb2BlockingSpec.groovy @@ -2,6 +2,7 @@ package org.prebid.server.functional.tests.module.ortb2blocking import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.bidder.Generic +import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.ExecutionPlan @@ -16,6 +17,8 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.Asset import org.prebid.server.functional.model.request.auction.Audio import org.prebid.server.functional.model.request.auction.Banner +import org.prebid.server.functional.model.request.auction.BidderControls +import org.prebid.server.functional.model.request.auction.GenericPreferredBidder import org.prebid.server.functional.model.request.auction.Ix import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Imp @@ -53,12 +56,12 @@ import static org.prebid.server.functional.testcontainers.Dependencies.getNetwor class Ortb2BlockingSpec extends ModuleBaseSpec { + private static final String WILDCARD = '*' private static final Map IX_CONFIG = ["adapters.ix.enabled" : "true", "adapters.ix.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - private static final String WILDCARD = '*' private final PrebidServerService pbsServiceWithEnabledOrtb2Blocking = pbsServiceFactory.getService(ortb2BlockingSettings + IX_CONFIG + - ["adapters.generic.ortb.multiformat-supported": "true"]) + ['adapter-defaults.ortb.multiformat-supported': 'false']) def "PBS should send original array ortb2 attribute to bidder when enforce blocking is disabled"() { given: "Default bid request with proper ortb attribute" @@ -131,6 +134,134 @@ class Ortb2BlockingSpec extends ModuleBaseSpec { PBSUtils.randomNumber | BTYPE } + def "PBS shouldn't be able to send original battr ortb2 attribute when bid request imps type doesn't match with attribute type"() { + given: "Account in the DB with blocking configuration" + def ortb2Attribute = PBSUtils.randomNumber + def account = getAccountWithOrtb2BlockingConfig(bidRequest.accountId, [ortb2Attribute], attributeName) + accountDao.save(account) + + and: "Default bidder response with ortb2 attributes" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + it.seatbid.first.bid = [getBidWithOrtb2Attribute(bidRequest.imp.first, ortb2Attribute, attributeName)] + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes the auction request" + def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + + then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert !bidderRequest?.imp?.first?.banner?.battr + assert !bidderRequest?.imp?.first?.video?.battr + assert !bidderRequest?.imp?.first?.audio?.battr + + and: "PBS request should contain single media type" + assert bidderRequest.imp.first.mediaTypes.size() == 1 + + and: "PBS response shouldn't contain any module errors" + assert !response?.ext?.prebid?.modules?.errors + + and: "PBS response shouldn't contain any module warning" + assert !response?.ext?.prebid?.modules?.warnings + + where: + bidRequest | attributeName + BidRequest.defaultVideoRequest | BANNER_BATTR + BidRequest.defaultAudioRequest | VIDEO_BATTR + BidRequest.defaultBidRequest | AUDIO_BATTR + } + + def "PBS shouldn't be able to send original battr ortb2 attribute when preferredMediaType doesn't match with attribute type"() { + given: "Default bid request with multiply types" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp.first.banner = Banner.defaultBanner + imp.first.video = Video.defaultVideo + imp.first.audio = Audio.defaultAudio + ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: preferredMediaType)) + } + + and: "Account in the DB with blocking configuration" + def ortb2Attribute = PBSUtils.randomNumber + def account = getAccountWithOrtb2BlockingConfig(bidRequest.accountId, [ortb2Attribute], attributeName) + accountDao.save(account) + + and: "Default bidder response with ortb2 attributes" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + it.seatbid.first.bid = [getBidWithOrtb2Attribute(bidRequest.imp.first, ortb2Attribute, attributeName)] + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes the auction request" + def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + + then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert !bidderRequest?.imp?.first?.banner?.battr + assert !bidderRequest?.imp?.first?.video?.battr + assert !bidderRequest?.imp?.first?.audio?.battr + + and: "PBS request should contain only preferred media type" + assert bidderRequest.imp.first.mediaTypes == [preferredMediaType] + + and: "PBS response shouldn't contain any module errors" + assert !response?.ext?.prebid?.modules?.errors + + and: "PBS response shouldn't contain any module warning" + assert !response?.ext?.prebid?.modules?.warnings + + where: + preferredMediaType | attributeName + VIDEO | BANNER_BATTR + AUDIO | VIDEO_BATTR + BANNER | AUDIO_BATTR + } + + def "PBS shouldn't be able to send original battr ortb2 attribute when account level preferredMediaType doesn't match with attribute type"() { + given: "Default bid request with multiply types" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp.first.banner = Banner.defaultBanner + imp.first.video = Video.defaultVideo + imp.first.audio = Audio.defaultAudio + } + + and: "Account in the DB with blocking configuration" + def ortb2Attribute = PBSUtils.randomNumber + def account = getAccountWithOrtb2BlockingConfig(bidRequest.accountId, [ortb2Attribute], attributeName).tap { + config.auction = new AccountAuctionConfig(preferredMediaType: [(GENERIC): preferredMediaType]) + } + accountDao.save(account) + + and: "Default bidder response with ortb2 attributes" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + it.seatbid.first.bid = [getBidWithOrtb2Attribute(bidRequest.imp.first, ortb2Attribute, attributeName)] + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes the auction request" + def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + + then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert !bidderRequest?.imp?.first?.banner?.battr + assert !bidderRequest?.imp?.first?.video?.battr + assert !bidderRequest?.imp?.first?.audio?.battr + + and: "PBS request should contain only preferred media type" + assert bidderRequest.imp.first.mediaTypes == [preferredMediaType] + + and: "PBS response shouldn't contain any module errors" + assert !response?.ext?.prebid?.modules?.errors + + and: "PBS response shouldn't contain any module warning" + assert !response?.ext?.prebid?.modules?.warnings + + where: + preferredMediaType | attributeName + VIDEO | BANNER_BATTR + AUDIO | VIDEO_BATTR + BANNER | AUDIO_BATTR + } + def "PBS shouldn't send original single ortb2 attribute to bidder when enforce blocking is disabled"() { given: "Default bid request with proper ortb attribute" def bidRequest = getBidRequestForOrtbAttribute(attributeName)