diff --git a/src/test/groovy/org/prebid/server/functional/model/config/PbResponseCorrection.groovy b/src/test/groovy/org/prebid/server/functional/model/config/PbResponseCorrection.groovy index 46af75deac6..f3171990d58 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/PbResponseCorrection.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/PbResponseCorrection.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.model.config +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString @@ -8,6 +9,8 @@ import groovy.transform.ToString @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy) class PbResponseCorrection { - Boolean enabled - AppVideoHtml appVideoHtml + Boolean enabled + AppVideoHtml appVideoHtml + @JsonProperty("suppress-ibv") + SuppressIbv suppressInBannerVideo } diff --git a/src/test/groovy/org/prebid/server/functional/model/config/SuppressIbv.groovy b/src/test/groovy/org/prebid/server/functional/model/config/SuppressIbv.groovy new file mode 100644 index 00000000000..5d19c3236a7 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/config/SuppressIbv.groovy @@ -0,0 +1,14 @@ +package org.prebid.server.functional.model.config + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName + +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) +class SuppressIbv { + + Boolean enabled + List excludedBidders +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidRejectionReason.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidRejectionReason.groovy index 2fb7d75bbf7..37d0a37947c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidRejectionReason.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidRejectionReason.groovy @@ -23,6 +23,9 @@ enum BidRejectionReason { RESPONSE_REJECTED_INVALID_CREATIVE(350), RESPONSE_REJECTED_INVALID_CREATIVE_SIZE(351), RESPONSE_REJECTED_INVALID_CREATIVE_NOT_SECURE(352), + + RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO(353), + RESPONSE_REJECTED_ADVERTISER_BLOCKED(356) @JsonValue diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/SeatNonBid.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/SeatNonBid.groovy index 16e1fd46459..a30917a18a6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/SeatNonBid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/SeatNonBid.groovy @@ -3,11 +3,12 @@ package org.prebid.server.functional.model.response.auction import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) class SeatNonBid { - String seat + BidderName seat List nonBid } diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy index e8151762026..7e5bf568795 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -1135,7 +1135,7 @@ class BidderParamsSpec extends BaseSpec { ["No match between the configured currencies and bidRequest.cur"] def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == BidderName.GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY @@ -1230,7 +1230,7 @@ class BidderParamsSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == BidderName.ALIAS.value + assert seatNonBid.seat == BidderName.ALIAS assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY diff --git a/src/test/groovy/org/prebid/server/functional/tests/SeatNonBidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SeatNonBidSpec.groovy index f6b02f22e76..8e945827c6d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SeatNonBidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SeatNonBidSpec.groovy @@ -1,6 +1,7 @@ package org.prebid.server.functional.tests import org.mockserver.model.HttpStatusCode +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountBidValidationConfig import org.prebid.server.functional.model.config.AccountConfig @@ -57,7 +58,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == ERROR_NO_BID @@ -83,7 +84,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == ERROR_INVALID_BID_RESPONSE } @@ -105,7 +106,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == ERROR_BIDDER_UNREACHABLE } @@ -138,7 +139,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE_SIZE } @@ -169,7 +170,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE_NOT_SECURE @@ -216,7 +217,7 @@ class SeatNonBidSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == ERROR_NO_BID @@ -277,7 +278,7 @@ class SeatNonBidSpec extends BaseSpec { assert seatNonBids.size() == 1 def seatNonBid = seatNonBids[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == ERROR_TIMED_OUT } @@ -301,7 +302,7 @@ class SeatNonBidSpec extends BaseSpec { assert seatNonBids.size() == 1 def seatNonBid = seatNonBids[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNSUPPORTED_MEDIA_TYPE 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 2b2de98750b..a7a97bc8816 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 @@ -1521,7 +1521,7 @@ class Ortb2BlockingSpec extends ModuleBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == ErrorType.GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_ADVERTISER_BLOCKED } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy index 1694a17dbaf..b13b0e75b34 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy @@ -1,14 +1,17 @@ package org.prebid.server.functional.tests.module.responsecorrenction +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.AppVideoHtml import org.prebid.server.functional.model.config.PbResponseCorrection import org.prebid.server.functional.model.config.PbsModulesConfig +import org.prebid.server.functional.model.config.SuppressIbv import org.prebid.server.functional.model.db.Account -import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Imp +import org.prebid.server.functional.model.request.auction.Native import org.prebid.server.functional.model.response.auction.Adm +import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidExt import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.Meta @@ -19,12 +22,13 @@ import org.prebid.server.functional.util.PBSUtils import java.time.Instant -import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.request.auction.BidRequest.getDefaultBidRequest import static org.prebid.server.functional.model.request.auction.BidRequest.getDefaultVideoRequest import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE +import static org.prebid.server.functional.model.response.auction.BidRejectionReason.* +import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC import static org.prebid.server.functional.model.response.auction.MediaType.AUDIO import static org.prebid.server.functional.model.response.auction.MediaType.BANNER import static org.prebid.server.functional.model.response.auction.MediaType.NATIVE @@ -57,7 +61,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest, responseCorrectionEnabled, appVideoHtmlEnabled) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId(), responseCorrectionEnabled, appVideoHtmlEnabled) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -100,7 +104,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -140,8 +144,8 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module and excluded bidders" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest).tap { - config.hooks.modules.pbResponseCorrection.appVideoHtml.excludedBidders = [GENERIC] + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()).tap { + config.hooks.modules.pbResponseCorrection.appVideoHtml.excludedBidders = [BidderName.GENERIC] } accountDao.save(accountWithResponseCorrectionModule) @@ -177,7 +181,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -216,7 +220,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -259,7 +263,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -300,7 +304,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -337,7 +341,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -384,7 +388,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -439,7 +443,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -494,7 +498,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -542,7 +546,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndAppVideoHtml(bidRequest.getAccountId()) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" @@ -576,10 +580,348 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { assert !response.ext.warnings } - private static Account accountConfigWithResponseCorrectionModule(BidRequest bidRequest, Boolean enabledResponseCorrection = true, Boolean enabledAppVideoHtml = true) { - def modulesConfig = new PbsModulesConfig(pbResponseCorrection: new PbResponseCorrection( - enabled: enabledResponseCorrection, appVideoHtml: new AppVideoHtml(enabled: enabledAppVideoHtml))) + def "PBS shouldn't reject auction with 353 code when enabled response correction is #enabledResponseCorrection and enabled suppress ibv is #enabledSuppressIbv"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId(), enabledResponseCorrection, enabledSuppressIbv) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "Response shouldn't contain errors" + assert !response.ext.errors + + and: "Response shouldn't contain warnings" + assert !response.ext.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + + and: "Bidder request should be invoke" + assert bidder.getBidderRequest(bidRequest.id) + + where: + enabledResponseCorrection | enabledSuppressIbv + false | true + true | false + false | false + } + + def "PBS shouldn't reject auction with 353 code when enabled suppress ibv and bid request with imp media type is #mediaType"() { + given: "Default bid request with APP" + def bidRequest = getDefaultBidRequest(APP).tap { + imp[0] = Imp.getDefaultImpression(mediaType) + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "Response shouldn't contain errors" + assert !response.ext.errors + + and: "Response shouldn't contain warnings" + assert !response.ext.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + + and: "Bidder request should be invoke" + assert bidder.getBidderRequest(bidRequest.id) + + where: + mediaType << [VIDEO, NATIVE, AUDIO] + } + + def "PBS shouldn't reject auction with 353 code when enabled suppress ibv and bis response with meta media type is #mediaType"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: mediaType.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "Response shouldn't contain errors" + assert !response.ext.errors + + and: "Response shouldn't contain warnings" + assert !response.ext.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + + and: "Bidder request should be invoke" + assert bidder.getBidderRequest(bidRequest.id) + + where: + mediaType << [BANNER, NATIVE, AUDIO] + } + + def "PBS shouldn't reject auction with 353 code when requested bidder is excluded"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()).tap { + config.hooks.modules.pbResponseCorrection.suppressInBannerVideo.excludedBidders = bidderName + } + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "Response shouldn't contain errors" + assert !response.ext.errors + + and: "Response shouldn't contain warnings" + assert !response.ext.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + + and: "Bidder request should be invoke" + assert bidder.getBidderRequest(bidRequest.id) + + where: + bidderName << [[BidderName.GENERIC_CAMEL_CASE, BidderName.GENERIC], + [BidderName.GENERIC], + [BidderName.GENERIC, BidderName.OPENX], + [BidderName.OPENX, BidderName.GENERIC], + [BidderName.GENERIC_CAMEL_CASE], + [BidderName.GENERIC, BidderName.GENERIC_CAMEL_CASE],] + } + + def "PBS should reject auction with 353 code when enabled suppress ibv and imp with media type Banner and bid response meta media type with Video and excluded bidder are not in case"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()).tap { + config.hooks.modules.pbResponseCorrection.suppressInBannerVideo.excludedBidders = bidderName + } + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS response should contain seatNonBid for called bidder" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == BidderName.GENERIC + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO + + and: "Seat bid should be empty" + assert response.seatbid.isEmpty() + + where: + bidderName << [[], [BidderName.GENER_X], [BidderName.WILDCARD], [BidderName.UNKNOWN, BidderName.BOGUS]] + } + + def "PBS should reject auction with 353 code when enabled suppress ibv and imp with media type Banner and bid response meta media type with Video"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + ext.prebid.returnAllBidStatus = true + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS response should contain seatNonBid for called bidder" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == BidderName.GENERIC + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO + + and: "Seat bid should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should reject auction with 353 code when enabled suppress ibv and multi-imp with different media type and bid response meta media type with Video"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + imp.add(Imp.getDefaultImpression(VIDEO)) + imp.add(Imp.getDefaultImpression(AUDIO)) + imp.add(Imp.getDefaultImpression(NATIVE)) + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS response should contain seatNonBid for called bidder" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == BidderName.GENERIC + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO + + and: "Seat bid should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should reject auction with 353 code when enabled suppress ibv and multi-imp with Banner media type and bid response meta media type with Video"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + imp.add(Imp.getDefaultImpression(BANNER)) + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS response should contain seatNonBid for called bidder" + assert response.ext.seatnonbid.size() == 2 + + def seatNonBid = response.ext.seatnonbid + assert seatNonBid.seat == [BidderName.GENERIC, BidderName.GENERIC] + assert seatNonBid.nonBid[0].impId == [bidRequest.imp[0].id, bidRequest.imp[1].id] + assert seatNonBid.nonBid[0].statusCode == [RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO, RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO] + + and: "Seat bid should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should reject auction with 353 code when enabled suppress ibv and multi-imp with multi-bid response media type and bid response meta media type with Video"() { + given: "Default bid request with banner and APP" + def bidRequest = getDefaultBidRequest(APP).tap { + imp.add(Imp.getDefaultImpression(BANNER)) + } + + and: "Save account with enabled response correction module and suppress ibv" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModuleAndSuppressIbv(bidRequest.getAccountId()) + accountDao.save(accountWithResponseCorrectionModule) + + and: "Set bidder response with meta media type" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: VIDEO.value))) + seatbid[0].bid[1].ext = new BidExt(prebid: new Prebid(meta: new Meta(mediaType: BANNER.value))) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS response should contain seatNonBid for called bidder" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid + assert seatNonBid.seat == [BidderName.GENERIC] + assert seatNonBid.nonBid[0].impId == [bidRequest.imp[0].id] + assert seatNonBid.nonBid[0].statusCode == [RESPONSE_REJECTED_DUE_TO_IN_BANNER_VIDEO] + + and: "Seat bid should be empty" + assert response.seatbid.isEmpty() + } + + private static Account accountConfigWithResponseCorrectionModuleAndAppVideoHtml(String accountId, boolean enabledResponseCorrection = true, boolean enabledAppVideoHtml = true) { + accountConfigWithResponseCorrectionModule(accountId, enabledResponseCorrection, enabledAppVideoHtml, false) + } + + private static Account accountConfigWithResponseCorrectionModuleAndSuppressIbv(String accountId, boolean enabledResponseCorrection = true, boolean enabledSuppressIbv = true) { + accountConfigWithResponseCorrectionModule(accountId, enabledResponseCorrection, false, enabledSuppressIbv) + } + + private static Account accountConfigWithResponseCorrectionModule(String accountId, boolean enabledResponseCorrection, boolean enabledAppVideoHtml = true, boolean enabledSuppressIbv) { + def pbResponseCorrection = new PbResponseCorrection().tap { + enabled = enabledResponseCorrection + appVideoHtml = new AppVideoHtml(enabled: enabledAppVideoHtml) + suppressInBannerVideo = new SuppressIbv(enabled: enabledSuppressIbv) + } + def modulesConfig = new PbsModulesConfig(pbResponseCorrection: pbResponseCorrection) def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: modulesConfig)) - new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + new Account(uuid: accountId, config: accountConfig) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/richmedia/RichMediaFilterSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/richmedia/RichMediaFilterSpec.groovy index 7c6e90d263e..996ebb5af99 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/richmedia/RichMediaFilterSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/richmedia/RichMediaFilterSpec.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.tests.module.richmedia +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.ExecutionPlan @@ -29,7 +30,7 @@ class RichMediaFilterSpec extends ModuleBaseSpec { private static final String PATTERN_NAME_ACCOUNT = PBSUtils.randomString private static final Map DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME, false) private static final Map SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME) - private static final Map SNAKE_SPECIFIC_PATTERN_NAME_CONFIG = (getRichMediaFilterSettings(PATTERN_NAME) + + private static final Map SNAKE_SPECIFIC_PATTERN_NAME_CONFIG = (getRichMediaFilterSettings(PATTERN_NAME) + ["hooks.host-execution-plan": encode(ExecutionPlan.getSingleEndpointExecutionPlan(OPENRTB2_AUCTION, PB_RICHMEDIA_FILTER, [ALL_PROCESSED_BID_RESPONSES]).tap { endpoints.values().first().stages.values().first().groups.first.hookSequenceSnakeCase = [new HookId(moduleCodeSnakeCase: PB_RICHMEDIA_FILTER.code, hookImplCodeSnakeCase: "${PB_RICHMEDIA_FILTER.code}-${ALL_PROCESSED_BID_RESPONSES.value}-hook")] })]).collectEntries { key, value -> [(key.toString()): value.toString()] } @@ -155,7 +156,7 @@ class RichMediaFilterSpec extends ModuleBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE @@ -239,7 +240,7 @@ class RichMediaFilterSpec extends ModuleBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE @@ -323,7 +324,7 @@ class RichMediaFilterSpec extends ModuleBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE @@ -440,7 +441,7 @@ class RichMediaFilterSpec extends ModuleBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_INVALID_CREATIVE diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy index e493bbb7df9..23f7a87ce23 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy @@ -951,7 +951,7 @@ class PriceFloorsRulesSpec extends PriceFloorsBaseSpec { assert seatNonBids.size() == 1 def seatNonBid = seatNonBids[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_PRICE_FLOOR assert seatNonBid.nonBid.size() == bidResponse.seatbid[0].bid.size() diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy index 2575789049d..612edd64b8b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.tests.privacy +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.config.AccountDsaConfig import org.prebid.server.functional.model.db.StoredRequest import org.prebid.server.functional.model.request.amp.AmpRequest @@ -315,7 +316,7 @@ class DsaSpec extends PrivacyBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_DSA @@ -495,7 +496,7 @@ class DsaSpec extends PrivacyBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_DSA @@ -535,7 +536,7 @@ class DsaSpec extends PrivacyBaseSpec { assert response.ext.seatnonbid.size() == 1 def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == BidderName.GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_DUE_TO_DSA diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy index 7302ad79aed..21e8ae7c02d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy @@ -267,11 +267,11 @@ class GdprAuctionSpec extends PrivacyBaseSpec { assert seatNonBids.size() == 1 def seatNonBid = seatNonBids[0] - assert seatNonBid.seat == GENERIC.value + assert seatNonBid.seat == GENERIC assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_PRIVACY - and: "seatbid should be empty" + and: "Seat bid should be empty" assert response.seatbid.isEmpty() }