From 4c2fdeeea99613dc895531eebe6a31d65b12257c Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 17 Jan 2025 15:28:40 +0200 Subject: [PATCH 01/18] WIP: initial commit --- .../model/config/AlternateBidderCodes.groovy | 16 + .../model/config/BidderConfig.groovy | 16 + .../server/functional/model/db/Account.groovy | 3 + .../model/request/auction/Prebid.groovy | 2 + .../model/response/auction/Meta.groovy | 2 + .../tests/AlternateBidderCodeSpec.groovy | 292 ++++++++++++++++++ .../functional/tests/BidderParamsSpec.groovy | 50 ++- 7 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/config/AlternateBidderCodes.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AlternateBidderCodes.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AlternateBidderCodes.groovy new file mode 100644 index 00000000000..465acaad2cc --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/config/AlternateBidderCodes.groovy @@ -0,0 +1,16 @@ +package org.prebid.server.functional.model.config + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName + +@EqualsAndHashCode +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy) +class AlternateBidderCodes { + + Boolean enabled + Map bidders +} diff --git a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy new file mode 100644 index 00000000000..3ace45da056 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy @@ -0,0 +1,16 @@ +package org.prebid.server.functional.model.config + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName + +@EqualsAndHashCode +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy) +class BidderConfig { + + Boolean enabled + List allowedBidderCodes +} diff --git a/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy b/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy index 834cb57c114..7593e85bfd0 100644 --- a/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy @@ -51,6 +51,9 @@ class Account { @Column(name = "config") @Convert(converter = AccountConfigTypeConverter) AccountConfig config + /* @Column(name = "alternate_bidder_codes") + @Convert(converter = AlternateBidderCodeSpec) + AlternateBidderCodeSpec alternateBidderCodes*/ @Column(name = "updated_by") Integer updatedBy @Column(name = "updated_by_user") diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index ba89f5680fa..86a3ce4306c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString import org.prebid.server.functional.model.ChannelType import org.prebid.server.functional.model.bidder.BidderName +import org.prebid.server.functional.model.config.AlternateBidderCodes @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) @ToString(includeNames = true, ignoreNulls = true) @@ -40,6 +41,7 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse + AlternateBidderCodes alternateBidderCodes static class Channel { diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy index d022daf9646..ffe2bedc060 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy @@ -1,11 +1,13 @@ package org.prebid.server.functional.model.response.auction +import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.ToString import org.prebid.server.functional.model.request.auction.RendererData @ToString(includeNames = true, ignoreNulls = true) class Meta { + @JsonProperty("adaptercode") String adapterCode List advertiserDomains Integer advertiserId diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy new file mode 100644 index 00000000000..895f195f545 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -0,0 +1,292 @@ +package org.prebid.server.functional.tests + +import org.prebid.server.functional.model.bidder.Openx +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AlternateBidderCodes +import org.prebid.server.functional.model.config.BidderConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.auction.BidRequest + +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.bidder.BidderName.OPENX +import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN +import static org.prebid.server.functional.model.privacy.Metric.ALERT_GENERAL +import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer + +class AlternateBidderCodeSpec extends BaseSpec { + + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes disabled"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = configuredBidderCode(defaultAccountAlternateBidderCodes) + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes.enabled = configuredBidderCode(requestedAlternateBidderCodes) + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = configuredBidderCode(accountAlternateBidderCodes) + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + false | false | false + null | false | false + false | null | false + false | false | null + false | true | false + true | true | false + true | null | false + } + + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes not fully configured"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = configuredBidderCode(defaultAccountAlternateBidderCodes) + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes.enabled = configuredBidderCode(requestedAlternateBidderCodes) + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = configuredBidderCode(accountAlternateBidderCodes) + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + then: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + new AlternateBidderCodes() | null | null + null | new AlternateBidderCodes() | null + null | null | new AlternateBidderCodes() + new AlternateBidderCodes(enabled: true) | null | null + null | new AlternateBidderCodes(enabled: true) | null + null | null | new AlternateBidderCodes(enabled: true) + null | null | null + new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null | null + null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null + null | null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) + new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null | null + null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + null | null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + } + + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and bidder disabled "() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() + null | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() + disabledGenericBidderConfiguredBidderCode() | null | disabledGenericBidderConfiguredBidderCode() + disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null + } + + def "PBS shouldn't throw out bid and emit response warning when configured alternate bidder codes with requested mismatch bidder"() { + given: "Pbs config with alternate bidder codes and openx" + def pbsService = pbsServiceFactory.getService( + ["adapters.openx.enabled" : "true", + "adapters.openx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with openx bidder and alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [OPENX] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = OPENX + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCode() | enabledConfiguredBidderCode() | enabledConfiguredBidderCode() + null | enabledConfiguredBidderCode() | enabledConfiguredBidderCode() + enabledConfiguredBidderCode() | null | enabledConfiguredBidderCode() + enabledConfiguredBidderCode() | enabledConfiguredBidderCode() | null + } + + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and bidder disabled"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() + null | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() + disabledGenericBidderConfiguredBidderCode() | null | disabledGenericBidderConfiguredBidderCode() + disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null + } + + private static AlternateBidderCodes enabledConfiguredBidderCode(Boolean alternateBidderCodesEnabled = true) { + new AlternateBidderCodes().tap { + it.enabled = alternateBidderCodesEnabled + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] + } + } + + private static AlternateBidderCodes disabledGenericBidderConfiguredBidderCode() { + new AlternateBidderCodes().tap { + it.enabled = true + it.bidders = [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])] + } + } +} 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 cab50bd816b..c2ddb4b52eb 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -30,7 +30,7 @@ import static org.prebid.server.functional.model.Currency.CHF import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD -import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS +import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP import static org.prebid.server.functional.model.bidder.CompressionType.NONE import static org.prebid.server.functional.model.request.auction.Asset.titleAsset @@ -847,7 +847,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted not specified"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "") @@ -955,7 +955,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted intersect with requested currency"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${USD},${EUR}".toString()) @@ -996,7 +996,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.aliases.bidder.meta-info.currency-accepted not intersect with requested currency"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${JPY},${CHF}".toString()) @@ -1040,4 +1040,46 @@ class BidderParamsSpec extends BaseSpec { assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY } + + def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode"() { + given: "Default basic BidRequest with stored response" + def bidRequest = BidRequest.defaultBidRequest + + bidder.reset() + + and: "Default bid response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].seat = OPENX + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + } + + def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested alias"() { + given: "Default bid request with alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } } From b0059932f7c4ea35972cac398301c380be2e0e94 Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 21 Jan 2025 15:01:54 +0200 Subject: [PATCH 02/18] Add a positive test cases --- .../tests/AlternateBidderCodeSpec.groovy | 244 +++++++++++++++++- 1 file changed, 233 insertions(+), 11 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 895f195f545..f503cfa2199 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -7,9 +7,11 @@ import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest +import static org.prebid.server.functional.model.bidder.BidderName.EMPTY import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN +import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD import static org.prebid.server.functional.model.privacy.Metric.ALERT_GENERAL import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer @@ -97,7 +99,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid[0].seat = GENERIC - + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -172,6 +174,9 @@ class AlternateBidderCodeSpec extends BaseSpec { null | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() disabledGenericBidderConfiguredBidderCode() | null | disabledGenericBidderConfiguredBidderCode() disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null + disabledGenericBidderConfiguredBidderCode() | null | null + null | disabledGenericBidderConfiguredBidderCode() | null + null | null | disabledGenericBidderConfiguredBidderCode() } def "PBS shouldn't throw out bid and emit response warning when configured alternate bidder codes with requested mismatch bidder"() { @@ -199,7 +204,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Flash metrics" flushMetrics(pbsService) - + when: "PBS processes auction request" def response = pbsService.sendAuctionRequest(bidRequest) @@ -211,7 +216,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response shouldn't contain warnings" assert !response.ext?.warnings - + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -220,11 +225,14 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCode() | enabledConfiguredBidderCode() | enabledConfiguredBidderCode() - null | enabledConfiguredBidderCode() | enabledConfiguredBidderCode() - enabledConfiguredBidderCode() | null | enabledConfiguredBidderCode() - enabledConfiguredBidderCode() | enabledConfiguredBidderCode() | null + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | null + null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null + null | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() } def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and bidder disabled"() { @@ -248,7 +256,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Flash metrics" flushMetrics(pbsService) - + when: "PBS processes auction request" def response = pbsService.sendAuctionRequest(bidRequest) @@ -260,7 +268,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response shouldn't contain warnings" assert !response.ext?.warnings - + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -276,13 +284,227 @@ class AlternateBidderCodeSpec extends BaseSpec { disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null } - private static AlternateBidderCodes enabledConfiguredBidderCode(Boolean alternateBidderCodesEnabled = true) { + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is wildcard"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | null | null + null | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | null + null | null | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() + enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() + } + + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is same as bidder requested"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat = GENERIC + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + + and: "Alert.general metric shouldn't be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | null | null + null | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | null + null | null | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() + enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() + } + + def "PBS should throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is empty"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain empty seatbid" + assert response.seatbid.isEmpty() + + and: "Bidder request shouldn't be valid" + assert !bidder.getBidderRequests(bidRequest.id) + + and: "Response should contain warnings" + assert response.ext?.warnings + + and: "Alert.general metric should be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | null | null + null | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | null + null | null | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() + enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() + } + + def "PBS should throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is unknown"() { + given: "Pbs config with alternate bidder codes" + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = defaultAccountAlternateBidderCodes + })]) + + and: "Default bid request with alternate bidder codes" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Save account config into DB with alternate bidder codes" + def account = new Account().tap { + uuid = bidRequest.accountId + alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Flash metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain empty seatbid" + assert response.seatbid.isEmpty() + + and: "Bidder request shouldn't be valid" + assert !bidder.getBidderRequests(bidRequest.id) + + and: "Response should contain warnings" + assert response.ext?.warnings + + and: "Alert.general metric should be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert metrics[ALERT_GENERAL] + + where: + requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null + null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | null + null | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + } + + private static AlternateBidderCodes enabledConfiguredBidderCodeWithUnknownAllowedBidderCode(Boolean alternateBidderCodesEnabled = true) { new AlternateBidderCodes().tap { it.enabled = alternateBidderCodesEnabled it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] } } + private static AlternateBidderCodes enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { + new AlternateBidderCodes().tap { + it.enabled = alternateBidderCodesEnabled + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [WILDCARD])] + } + } + + private static AlternateBidderCodes enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { + new AlternateBidderCodes().tap { + it.enabled = alternateBidderCodesEnabled + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [EMPTY])] + } + } + + private static AlternateBidderCodes enabledConfiguredBidderCodeWithGenericAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { + new AlternateBidderCodes().tap { + it.enabled = alternateBidderCodesEnabled + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } + } + private static AlternateBidderCodes disabledGenericBidderConfiguredBidderCode() { new AlternateBidderCodes().tap { it.enabled = true From 1bbe3fc10290248c8fb231729f580d0b8dd58cef Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 21 Jan 2025 15:05:08 +0200 Subject: [PATCH 03/18] Naming update --- .../prebid/server/functional/tests/BidderParamsSpec.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 c2ddb4b52eb..080045f3f77 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -1042,11 +1042,9 @@ class BidderParamsSpec extends BaseSpec { } def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode"() { - given: "Default basic BidRequest with stored response" + given: "Default basic bid request" def bidRequest = BidRequest.defaultBidRequest - bidder.reset() - and: "Default bid response" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { seatbid[0].seat = OPENX From 560a51364855dd29af00952d69ac2e845d913cbd Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 13 Feb 2025 16:34:10 +0200 Subject: [PATCH 04/18] Refactor functional tests --- .../model/config/AccountConfig.groovy | 2 + .../server/functional/model/db/Account.groovy | 3 - .../tests/AlternateBidderCodeSpec.groovy | 544 +++++++++--------- 3 files changed, 282 insertions(+), 267 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy index 60563ac2f5e..57de769c427 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy @@ -23,6 +23,8 @@ class AccountConfig { AccountSetting settings @JsonProperty("cookie_sync") AccountCookieSyncConfig cookieSyncSnakeCase + // Can be in other places + AlternateBidderCodes alternateBidderCodes static getDefaultAccountConfig() { new AccountConfig(status: AccountStatus.ACTIVE) diff --git a/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy b/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy index 7593e85bfd0..834cb57c114 100644 --- a/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/db/Account.groovy @@ -51,9 +51,6 @@ class Account { @Column(name = "config") @Convert(converter = AccountConfigTypeConverter) AccountConfig config - /* @Column(name = "alternate_bidder_codes") - @Convert(converter = AlternateBidderCodeSpec) - AlternateBidderCodeSpec alternateBidderCodes*/ @Column(name = "updated_by") Integer updatedBy @Column(name = "updated_by_user") diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index f503cfa2199..a6a2e41cd28 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -1,162 +1,166 @@ package org.prebid.server.functional.tests -import org.prebid.server.functional.model.bidder.Openx +import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AlternateBidderCodes import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.util.PBSUtils +import static org.prebid.server.functional.model.AccountStatus.ACTIVE +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.BOGUS import static org.prebid.server.functional.model.bidder.BidderName.EMPTY import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD import static org.prebid.server.functional.model.privacy.Metric.ALERT_GENERAL -import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID class AlternateBidderCodeSpec extends BaseSpec { - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes disabled"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = configuredBidderCode(defaultAccountAlternateBidderCodes) - })]) + private static final WARNING_MESSAGE = "HERE SHOULD BE WARNING" - and: "Default bid request with alternate bidder codes" + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes not fully configured"() { + given: "Default bid request with alternate bidder codes" def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes.enabled = configuredBidderCode(requestedAlternateBidderCodes) + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = configuredBidderCode(accountAlternateBidderCodes) + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes = accountAlternateBidderCodes } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC + assert response.seatbid[0].seat == GENERIC and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" + then: "Response shouldn't contain warnings" assert !response.ext?.warnings and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - false | false | false - null | false | false - false | null | false - false | false | null - false | true | false - true | true | false - true | null | false + requestedAlternateBidderCodes | accountAlternateBidderCodes + null | null + new AlternateBidderCodes() | null + null | new AlternateBidderCodes() + new AlternateBidderCodes(enabled: true) | null + new AlternateBidderCodes(enabled: false) | null + null | new AlternateBidderCodes(enabled: true) + null | new AlternateBidderCodes(enabled: false) + new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig()]) | null + null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) + null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig()]) + new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null + new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null + new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null + null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) + null | new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) + null | new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes not fully configured"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = configuredBidderCode(defaultAccountAlternateBidderCodes) - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes.enabled = configuredBidderCode(requestedAlternateBidderCodes) + def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes disabled"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = configuredBidderCode(accountAlternateBidderCodes) + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.enabled = accountAlternateBidderCodes } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] - and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC + and: "Response should contain seatBid.seat" + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings" + and: "Response shouldn't contain warnings" assert !response.ext?.warnings and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - new AlternateBidderCodes() | null | null - null | new AlternateBidderCodes() | null - null | null | new AlternateBidderCodes() - new AlternateBidderCodes(enabled: true) | null | null - null | new AlternateBidderCodes(enabled: true) | null - null | null | new AlternateBidderCodes(enabled: true) - null | null | null - new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null | null - null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null - null | null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) - new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null | null - null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - null | null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + requestedAlternateBidderCodes | accountAlternateBidderCodes + false | false + false | null + null | false + false | true } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and bidder disabled "() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS shouldn't discard the bid or emit a response warning warning when alternate bidder codes disabled for bidder"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders[GENERIC].enabled = requestedAlternateBidderCodes + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders[GENERIC].enabled = accountAlternateBidderCodes } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] - and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC + and: "Response should contain seatBid.seat" + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -165,54 +169,41 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !response.ext?.warnings and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() - null | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() - disabledGenericBidderConfiguredBidderCode() | null | disabledGenericBidderConfiguredBidderCode() - disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null - disabledGenericBidderConfiguredBidderCode() | null | null - null | disabledGenericBidderConfiguredBidderCode() | null - null | null | disabledGenericBidderConfiguredBidderCode() + requestedAlternateBidderCodes | accountAlternateBidderCodes + false | false + false | null + null | false + false | true } - def "PBS shouldn't throw out bid and emit response warning when configured alternate bidder codes with requested mismatch bidder"() { - given: "Pbs config with alternate bidder codes and openx" - def pbsService = pbsServiceFactory.getService( - ["adapters.openx.enabled" : "true", - "adapters.openx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with openx bidder and alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.generic = null - imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS shouldn't discard the bid or emit a response warning when configured alternate bidder codes with the requested mismatched bidder"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders = requestedAlternateBidderCodes + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders = accountAlternateBidderCodes } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [OPENX] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = OPENX + assert response.seatbid.seat.flatten() == [GENERIC] and: "Response shouldn't contain warnings" assert !response.ext?.warnings @@ -221,99 +212,94 @@ class AlternateBidderCodeSpec extends BaseSpec { assert bidder.getBidderRequests(bidRequest.id) and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | null - null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null - null | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + requestedAlternateBidderCodes | accountAlternateBidderCodes + [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | null + null | [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and bidder disabled"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = requestedAllowedBidderCodes + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = accountAllowedBidderCodes } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC - - and: "Response shouldn't contain warnings" - assert !response.ext?.warnings + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings + and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() - null | disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() - disabledGenericBidderConfiguredBidderCode() | null | disabledGenericBidderConfiguredBidderCode() - disabledGenericBidderConfiguredBidderCode() | disabledGenericBidderConfiguredBidderCode() | null + requestedAllowedBidderCodes | accountAllowedBidderCodes + [] | null + null | [] + [WILDCARD] | null + [WILDCARD, EMPTY] | null + [WILDCARD, EMPTY] | [WILDCARD, EMPTY] + null | [WILDCARD] + null | [WILDCARD, EMPTY] + null | null + [WILDCARD] | [WILDCARD] + [] | [] + [EMPTY] | [EMPTY] + [EMPTY] | null + null | [EMPTY] } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is wildcard"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders = requestAlternateBidders + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes + it.uuid = bidRequest.accountId + it.config = new AccountConfig(status: ACTIVE) + it.alternateBidderCodes = new AlternateBidderCodes(enabled: true, bidders: accountAlternateBidders) } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -322,35 +308,32 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !response.ext?.warnings and: "Alert.general metric shouldn't be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | null | null - null | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | null - null | null | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() - enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() | enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes() + accountAlternateBidders | requestAlternateBidders + [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null + [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | null + [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null + null | [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] + null | [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + null | [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is same as bidder requested"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS shouldn't discard the bid and emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes does match the bidder's request"() { + given: "Pbs config with default-account-config" + def defaultAccountConfig = AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = new AlternateBidderCodes().tap { + it.enabled = true + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } } + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(defaultAccountConfig)]) - and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes - } - accountDao.save(account) + and: "Default bid request" + def bidRequest = BidRequest.getDefaultBidRequest() and: "Flash metrics" flushMetrics(pbsService) @@ -362,90 +345,110 @@ class AlternateBidderCodeSpec extends BaseSpec { assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat = GENERIC + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) and: "Response shouldn't contain warnings" - assert !response.ext?.warnings + assert !response.ext?.warnings[PREBID] and: "Alert.general metric shouldn't be updated" def metrics = pbsService.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] - - where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | null | null - null | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | null - null | null | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() - enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() | enabledConfiguredBidderCodeWithGenericAllowedBidderCodes() } - def "PBS should throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is empty"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) + def "PBS shouldn't discard bid and not emit a response warning when requested alternate bidder codes are enabled and the allowed bidder code doesn't match with alias of specified bidders"() { + given: "Default bid request with alias and alternate bidder code" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.aliases = [(ALIAS.value): GENERIC] + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.generic = null + } - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Resolved request should contain aliases as in request" + assert response.ext.debug.resolvedRequest.ext.prebid.aliases == bidRequest.ext.prebid.aliases + + and: "Bidder request should contain request per-alies" + assert bidder.getBidderRequest(bidRequest.id) + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + + and: "Response should contain seatbid.seat" + assert response.seatbid.seat.flatten() == [ALIAS] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings" + assert !response.ext?.warnings[PREBID] + + and: "Alert.general metric shouldn't be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert !metrics[ALERT_GENERAL] + } + + def "PBS should discard the bid and emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = requestedAllowedBidderCode + setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = accountAllowedBidderCode } accountDao.save(account) and: "Flash metrics" - flushMetrics(pbsService) + flushMetrics(defaultPbsService) when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) - then: "Response should contain empty seatbid" - assert response.seatbid.isEmpty() + then: "Response shouldn't contain seat bid" + assert !response.seatbid - and: "Bidder request shouldn't be valid" - assert !bidder.getBidderRequests(bidRequest.id) + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) and: "Response should contain warnings" - assert response.ext?.warnings + assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] and: "Alert.general metric should be updated" - def metrics = pbsService.sendCollectedMetricsRequest() + def metrics = defaultPbsService.sendCollectedMetricsRequest() assert metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | null | null - null | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | null - null | null | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() - enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() | enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes() + requestedAllowedBidderCode | accountAllowedBidderCode + [UNKNOWN] | null + [BOGUS] | null + null | [BOGUS] + null | [UNKNOWN] + null | [UNKNOWN, BOGUS] + [UNKNOWN, BOGUS] | [GENERIC] + [UNKNOWN] | [GENERIC] } - def "PBS should throw out bid and emit response warning when alternate bidder codes enabled and allowed bidder codes is unknown"() { - given: "Pbs config with alternate bidder codes" - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(AccountConfig.defaultAccountConfig.tap { - alternateBidderCodes = defaultAccountAlternateBidderCodes - })]) - - and: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def "PBS should discard the bid and emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { + given: "Pbs config with default-account-config" + def defaultAccountConfig = AccountConfig.defaultAccountConfig.tap { + alternateBidderCodes = new AlternateBidderCodes().tap { + it.enabled = true + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: allowedBidderCodes)] + } } + def pbsService = pbsServiceFactory.getService( + ["settings.default-account-config": encode(defaultAccountConfig)]) - and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - uuid = bidRequest.accountId - alternateBidderCodes = accountAlternateBidderCodes - } - accountDao.save(account) + and: "Default bid request" + def bidRequest = BidRequest.getDefaultBidRequest() and: "Flash metrics" flushMetrics(pbsService) @@ -453,62 +456,75 @@ class AlternateBidderCodeSpec extends BaseSpec { when: "PBS processes auction request" def response = pbsService.sendAuctionRequest(bidRequest) - then: "Response should contain empty seatbid" - assert response.seatbid.isEmpty() + then: "Response shouldn't contain seat bid" + assert !response.seatbid - and: "Bidder request shouldn't be valid" - assert !bidder.getBidderRequests(bidRequest.id) + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) and: "Response should contain warnings" - assert response.ext?.warnings + assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] and: "Alert.general metric should be updated" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | defaultAccountAlternateBidderCodes | accountAlternateBidderCodes - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null - null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | null | null - null | null | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() - enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() | enabledConfiguredBidderCodeWithUnknownAllowedBidderCode() + allowedBidderCodes << [[BOGUS], [BOGUS, UNKNOWN]] } - private static AlternateBidderCodes enabledConfiguredBidderCodeWithUnknownAllowedBidderCode(Boolean alternateBidderCodesEnabled = true) { - new AlternateBidderCodes().tap { - it.enabled = alternateBidderCodesEnabled - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] + def "PBS should discard bid and not emit a response warning when requested alternate bidder codes are enabled and the allowed bidder code does match with alias of specified bidders"() { + given: "Default bid request with alias and alternate bidder code" + def bidRequest = bidRequestWithAlternateBidderCode().tap { + ext.prebid.aliases = [(ALIAS.value): GENERIC] + ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.generic = null } - } - private static AlternateBidderCodes enabledConfiguredBidderCodeWithWildcardAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { - new AlternateBidderCodes().tap { - it.enabled = alternateBidderCodesEnabled - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [WILDCARD])] - } - } + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) - private static AlternateBidderCodes enabledConfiguredBidderCodeWithEmptyAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { - new AlternateBidderCodes().tap { - it.enabled = alternateBidderCodesEnabled - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [EMPTY])] - } + then: "Resolved request should contain aliases as in request" + assert response.ext.debug.resolvedRequest.ext.prebid.aliases == bidRequest.ext.prebid.aliases + + and: "Response shouldn't contain seat bid" + assert !response.seatbid + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response should contain warnings" + assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] + + and: "Alert.general metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[ALERT_GENERAL] } - private static AlternateBidderCodes enabledConfiguredBidderCodeWithGenericAllowedBidderCodes(Boolean alternateBidderCodesEnabled = true) { - new AlternateBidderCodes().tap { - it.enabled = alternateBidderCodesEnabled - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + //todo: ADD test for it, if pubmatic bidder will be updated with logic for different seat name + // check for the existence of the seat-defined-bidderCode in the bidadjustmentfactors object. If it exists, apply the adjustment and we're done. + // otherwise, check for the existence of the adaptercode (seatbid.bid.ext.prebid.meta.adaptercode) in the bidadjustmentfactors object. If it exists, apply the adjustment + + private static Account accountWithAlternateBidderCode(BidRequest bidRequest) { + new Account().tap { + it.uuid = bidRequest.accountId + it.config = new AccountConfig(status: ACTIVE) + it.config = new AccountConfig(alternateBidderCodes: new AlternateBidderCodes().tap { + it.enabled = true + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + }) } } - private static AlternateBidderCodes disabledGenericBidderConfiguredBidderCode() { - new AlternateBidderCodes().tap { - it.enabled = true - it.bidders = [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])] + private static BidRequest bidRequestWithAlternateBidderCode() { + BidRequest.defaultBidRequest.tap { + it.ext.prebid.alternateBidderCodes = new AlternateBidderCodes().tap { + it.enabled = true + it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } } } } From cda98f6e7f67f20d7102435a35b684b6bb6386ef Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 13 Feb 2025 16:39:29 +0200 Subject: [PATCH 05/18] Update naming --- .../server/functional/tests/AlternateBidderCodeSpec.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index a6a2e41cd28..c4d79c71a58 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -24,7 +24,7 @@ class AlternateBidderCodeSpec extends BaseSpec { private static final WARNING_MESSAGE = "HERE SHOULD BE WARNING" - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes not fully configured"() { + def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes @@ -94,7 +94,7 @@ class AlternateBidderCodeSpec extends BaseSpec { null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) } - def "PBS shouldn't throw out bid and emit response warning when alternate bidder codes disabled"() { + def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes disabled"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes @@ -321,7 +321,7 @@ class AlternateBidderCodeSpec extends BaseSpec { null | [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] } - def "PBS shouldn't discard the bid and emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes does match the bidder's request"() { + def "PBS shouldn't discard the bid or emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes does match the bidder's request"() { given: "Pbs config with default-account-config" def defaultAccountConfig = AccountConfig.defaultAccountConfig.tap { alternateBidderCodes = new AlternateBidderCodes().tap { From 0c04b53ad053a77e76ce6858725e3d1d41098e90 Mon Sep 17 00:00:00 2001 From: markiian Date: Sat, 8 Mar 2025 21:36:55 +0200 Subject: [PATCH 06/18] Update functional tests --- .../functional/model/bidder/BidderName.groovy | 4 +- .../model/bidder/GeneralBidderAdapter.groovy | 2 + .../model/config/AccountConfig.groovy | 1 - .../model/request/auction/Amx.groovy | 17 + .../model/request/auction/Bidder.groovy | 1 + .../model/request/auction/Prebid.groovy | 4 +- .../model/response/auction/BidExt.groovy | 10 + .../model/response/auction/ErrorType.groovy | 3 +- .../model/response/auction/Meta.groovy | 3 +- .../tests/AlternateBidderCodeSpec.groovy | 693 +++++++++++------- .../functional/tests/BidAdjustmentSpec.groovy | 76 +- .../functional/tests/BidderParamsSpec.groovy | 5 +- 12 files changed, 558 insertions(+), 261 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/request/auction/Amx.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy index 54e0a451fc6..3cd339b7378 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy @@ -25,7 +25,9 @@ enum BidderName { ADKERNEL("adkernel"), IX("ix"), GRID("grid"), - MEDIANET("medianet") + MEDIANET("medianet"), + AMX("amx"), + AMX_CAMEL_CASE("AmX"), @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy index 3184fb17fee..50d4f960327 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy @@ -5,4 +5,6 @@ class GeneralBidderAdapter extends Generic { String siteId List size String sid + String ds + String bc } diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy index 57de769c427..e690f070db8 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy @@ -23,7 +23,6 @@ class AccountConfig { AccountSetting settings @JsonProperty("cookie_sync") AccountCookieSyncConfig cookieSyncSnakeCase - // Can be in other places AlternateBidderCodes alternateBidderCodes static getDefaultAccountConfig() { diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Amx.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Amx.groovy new file mode 100644 index 00000000000..3ae0dcd17a3 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Amx.groovy @@ -0,0 +1,17 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonProperty +import org.prebid.server.functional.model.bidder.BidderAdapter +import org.prebid.server.functional.model.bidder.BidderName + +class Amx implements BidderAdapter { + + @JsonProperty("ct") + Integer creativeType + @JsonProperty("startdelay") + Integer startDelay + @JsonProperty("ds") + String demandSource + @JsonProperty("bc") + BidderName bidderCode +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy index 125faa37c4b..05723387d5d 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy @@ -26,6 +26,7 @@ class Bidder { Openx openxAlias Adrino adrino Generic nativo + Amx amx static Bidder getDefaultBidder() { new Bidder().tap { diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index e4bc02e0129..c3faf956f9f 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.model.request.auction +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString @@ -30,7 +31,7 @@ class Prebid { List multibid Pbs pbs Server server - Map> bidderParams + Map bidderParams ExtPrebidFloors floors Map passThrough Events events @@ -41,6 +42,7 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse + @JsonProperty("alternatebidderscodes") AlternateBidderCodes alternateBidderCodes PaaFormat paaFormat diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidExt.groovy index 61cdd7ad5f0..58d2e2178e3 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidExt.groovy @@ -1,7 +1,9 @@ package org.prebid.server.functional.model.response.auction +import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.ToString import org.prebid.server.functional.model.Currency +import org.prebid.server.functional.model.bidder.BidderName @ToString(includeNames = true, ignoreNulls = true) class BidExt { @@ -10,4 +12,12 @@ class BidExt { BigDecimal origbidcpm Currency origbidcur DsaResponse dsa + @JsonProperty("ct") + Integer creativeType + @JsonProperty("startdelay") + Integer startDelay + @JsonProperty("ds") + String demandSource + @JsonProperty("bc") + BidderName bidderCode } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy index 267a23cc067..039aa5aca2a 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy @@ -14,7 +14,8 @@ enum ErrorType { ALIAS("alias"), TARGETING("targeting"), IX("ix"), - OPENX("openx") + OPENX("openx"), + AMX("amx"), @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy index ffe2bedc060..e8bb869ebae 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/Meta.groovy @@ -2,13 +2,14 @@ package org.prebid.server.functional.model.response.auction import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.request.auction.RendererData @ToString(includeNames = true, ignoreNulls = true) class Meta { @JsonProperty("adaptercode") - String adapterCode + BidderName adapterCode List advertiserDomains Integer advertiserId String advertiserName diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index c4d79c71a58..7546655480f 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -1,261 +1,405 @@ package org.prebid.server.functional.tests +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AlternateBidderCodes import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.auction.Amx import org.prebid.server.functional.model.request.auction.BidRequest +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.ErrorType +import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils +import spock.lang.Shared import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_CAMEL_CASE +import static org.prebid.server.functional.model.bidder.BidderName.AMX +import static org.prebid.server.functional.model.bidder.BidderName.AMX_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.BOGUS import static org.prebid.server.functional.model.bidder.BidderName.EMPTY -import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE -import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD import static org.prebid.server.functional.model.privacy.Metric.ALERT_GENERAL -import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.BidRejectionReason.RESPONSE_REJECTED_GENERAL +import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class AlternateBidderCodeSpec extends BaseSpec { - private static final WARNING_MESSAGE = "HERE SHOULD BE WARNING" + private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { - given: "Default bid request with alternate bidder codes" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes - setAccountId(PBSUtils.randomString) - } + @Shared + PrebidServerService pbsServiceWithAmxBidder = pbsServiceFactory.getService(AMX_CONFIG) - and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes = accountAlternateBidderCodes + @Override + def cleanupSpec() { + pbsServiceFactory.removeContainer(AMX_CONFIG) + } + + def "PBS shouldn't discard bid for amx bidder same seat in response as seat in bid.ext.bidderCode"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder() + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: bidderCode) } - accountDao.save(account) + bidder.setResponse(bidRequest.id, bidResponse) and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + then: "Bid response should contain exp data" + assert response.seatbid.seat == [AMX] - and: "Response should contain seatbid.seat" - assert response.seatbid[0].seat == GENERIC + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings" + and: "Response shouldn't contain warnings and error and seatNonBid" assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] where: - requestedAlternateBidderCodes | accountAlternateBidderCodes - null | null - new AlternateBidderCodes() | null - null | new AlternateBidderCodes() - new AlternateBidderCodes(enabled: true) | null - new AlternateBidderCodes(enabled: false) | null - null | new AlternateBidderCodes(enabled: true) - null | new AlternateBidderCodes(enabled: false) - new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) | null - new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig()]) | null - null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig()]) - null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig()]) - new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null - new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null - new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) | null - null | new AlternateBidderCodes(bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) - null | new AlternateBidderCodes(enabled: false, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) - null | new AlternateBidderCodes(enabled: true, bidders: [(GENERIC): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [GENERIC])]) + bidderCode << [AMX, AMX_CAMEL_CASE] } - def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes disabled"() { - given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes - setAccountId(PBSUtils.randomString) + def "PBS should discard bid for amx bidder when imp[].bidder isn't same as in bid.ext.bidderCode"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder() + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: bidderName) } + bidder.setResponse(bidRequest.id, bidResponse) - and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes.enabled = accountAlternateBidderCodes + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() + + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL + + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${bidderName} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${bidderName} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "PBS should emit metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] + + where: + bidderName << [BOGUS, UNKNOWN, WILDCARD] + } + + def "PBS should discard bid amx alias requested when imp[].bidder isn't same as in bid.ext.bidderCode"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + ext.prebid.aliases = [(ALIAS.value): AMX] } - accountDao.save(account) + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: bidderName) + } + bidder.setResponse(bidRequest.id, bidResponse) and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() + + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == ALIAS.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL + + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.ALIAS][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${bidderName} was set by the adapter ${ALIAS} for the account ${bidRequest.accountId}" - and: "Response should contain seatBid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${bidderName} was set by the adapter ${ALIAS} for the account ${bidRequest.accountId}") and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" + and: "PBS should emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${ALIAS}.response.validation.seat"] + + where: + bidderName << [BOGUS, UNKNOWN, WILDCARD] + } + + def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + ext.prebid.aliases = [(ALIAS.value): AMX] + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: bidderCode) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain exp data" + assert response.seatbid.seat == [ALIAS] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${ALIAS}.response.validation.seat"] where: - requestedAlternateBidderCodes | accountAlternateBidderCodes - false | false - false | null - null | false - false | true + bidderCode << [ALIAS, ALIAS_CAMEL_CASE] } - def "PBS shouldn't discard the bid or emit a response warning warning when alternate bidder codes disabled for bidder"() { + def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders[GENERIC].enabled = requestedAlternateBidderCodes + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes.bidders[GENERIC].enabled = accountAlternateBidderCodes + config.alternateBidderCodes = accountAlternateBidderCodes } accountDao.save(account) + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: AMX) + } + bidder.setResponse(bidRequest.id, bidResponse) + and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] - and: "Response should contain seatBid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat == AMX and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" + then: "Response shouldn't contain warnings" assert !response.ext?.warnings and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() assert !metrics[ALERT_GENERAL] where: - requestedAlternateBidderCodes | accountAlternateBidderCodes - false | false - false | null - null | false - false | true + requestedAlternateBidderCodes | accountAlternateBidderCodes + null | null + new AlternateBidderCodes() | null + null | new AlternateBidderCodes() + new AlternateBidderCodes(enabled: true) | null + new AlternateBidderCodes(enabled: false) | null + null | new AlternateBidderCodes(enabled: true) + null | new AlternateBidderCodes(enabled: false) + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]) | null + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) | null + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]) | null + null | new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]) + null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) + null | new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]) + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null + null | new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) + null | new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) + null | new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) + null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) } - def "PBS shouldn't discard the bid or emit a response warning when configured alternate bidder codes with the requested mismatched bidder"() { + def "PBS should discard the bid and emit a response warning when alternate bidder codes disabled and bidder came with different bidderCode"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders = requestedAlternateBidderCodes + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes.bidders = accountAlternateBidderCodes + config.alternateBidderCodes.enabled = accountAlternateBidderCodes } accountDao.save(account) + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: UNKNOWN) + } + bidder.setResponse(bidRequest.id, bidResponse) + and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() - and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 - and: "Response shouldn't contain warnings" - assert !response.ext?.warnings + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL + + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + + and: "PBS should emit metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] - where: - requestedAlternateBidderCodes | accountAlternateBidderCodes - [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | null - null | [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] - [(OPENX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] + requestedAlternateBidderCodes | accountAlternateBidderCodes + false | false + false | null + null | false } def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = requestedAllowedBidderCodes + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodes = requestedAllowedBidderCodes setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = accountAllowedBidderCodes + config.alternateBidderCodes.bidders[AMX].allowedBidderCodes = accountAllowedBidderCodes } accountDao.save(account) + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: AMX) + } + bidder.setResponse(bidRequest.id, bidResponse) + and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + assert response.seatbid.seat.flatten() == [AMX] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" + and: "Response shouldn't contain warnings and errors and seatNonBid" assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + and: "PBs metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] where: requestedAllowedBidderCodes | accountAllowedBidderCodes @@ -276,64 +420,80 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders = requestAlternateBidders setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = new Account().tap { - it.uuid = bidRequest.accountId - it.config = new AccountConfig(status: ACTIVE) - it.alternateBidderCodes = new AlternateBidderCodes(enabled: true, bidders: accountAlternateBidders) + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders = accountAlternateBidders } accountDao.save(account) + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: BidderName.GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + assert response.seatbid.seat.flatten() == [BidderName.GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" + and: "Response shouldn't contain warnings and errors and seatNonBid" assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + and: "PBs metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] where: - accountAlternateBidders | requestAlternateBidders - [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null - [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] | null - [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null - null | [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] - null | [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] - null | [(GENERIC_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] + accountAlternateBidders | requestAlternateBidders + [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] | null + [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] | null + null | [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] + null | [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] + null | [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] + null | [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] } - def "PBS shouldn't discard the bid or emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes does match the bidder's request"() { - given: "Pbs config with default-account-config" + def "PBS shouldn't discard the bid or emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes match the bidder's request"() { + given: "Pbs config with default-account-config of alternate bidder code" def defaultAccountConfig = AccountConfig.defaultAccountConfig.tap { alternateBidderCodes = new AlternateBidderCodes().tap { it.enabled = true - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + it.bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] } } - def pbsService = pbsServiceFactory.getService( - ["settings.default-account-config": encode(defaultAccountConfig)]) + def config = AMX_CONFIG + ["settings.default-account-config": encode(defaultAccountConfig)] + def pbsService = pbsServiceFactory.getService(config) and: "Default bid request" - def bidRequest = BidRequest.getDefaultBidRequest() + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes = null + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: AMX) + } + bidder.setResponse(bidRequest.id, bidResponse) and: "Flash metrics" flushMetrics(pbsService) @@ -342,98 +502,129 @@ class AlternateBidderCodeSpec extends BaseSpec { def response = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [GENERIC] + assert response.seatbid.seat.flatten() == [AMX] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" - assert !response.ext?.warnings[PREBID] + and: "Response shouldn't contain warnings and errors and seatnonbid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid and: "Alert.general metric shouldn't be updated" def metrics = pbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + assert !metrics["adapter.${AMX}.response.validation.seat"] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(config) } - def "PBS shouldn't discard bid and not emit a response warning when requested alternate bidder codes are enabled and the allowed bidder code doesn't match with alias of specified bidders"() { - given: "Default bid request with alias and alternate bidder code" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.aliases = [(ALIAS.value): GENERIC] - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.generic = null + def "PBS should discard the bid and emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + setAccountId(PBSUtils.randomString) } + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: requestedAllowedBidderCode) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Resolved request should contain aliases as in request" - assert response.ext.debug.resolvedRequest.ext.prebid.aliases == bidRequest.ext.prebid.aliases + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() - and: "Bidder request should contain request per-alies" - assert bidder.getBidderRequest(bidRequest.id) + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 - and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL - and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [ALIAS] + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + + and: "PBS should emit metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response shouldn't contain warnings" - assert !response.ext?.warnings[PREBID] - - and: "Alert.general metric shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + where: + requestedAllowedBidderCode << [UNKNOWN, BOGUS] } def "PBS should discard the bid and emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = requestedAllowedBidderCode + def bidRequest = bidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { - config.alternateBidderCodes.bidders[GENERIC].allowedBidderCodes = accountAllowedBidderCode - } + def account = accountWithAlternateBidderCode(bidRequest) accountDao.save(account) + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: requestedAllowedBidderCode) + } + bidder.setResponse(bidRequest.id, bidResponse) + and: "Flash metrics" - flushMetrics(defaultPbsService) + flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Response shouldn't contain seat bid" - assert !response.seatbid + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL + + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") - and: "Response should contain warnings" - assert response.ext?.warnings[PREBID]*.code == [999] - assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] + and: "PBS should emit metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] - and: "Alert.general metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[ALERT_GENERAL] + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) where: - requestedAllowedBidderCode | accountAllowedBidderCode - [UNKNOWN] | null - [BOGUS] | null - null | [BOGUS] - null | [UNKNOWN] - null | [UNKNOWN, BOGUS] - [UNKNOWN, BOGUS] | [GENERIC] - [UNKNOWN] | [GENERIC] + requestedAllowedBidderCode << [UNKNOWN, BOGUS] } def "PBS should discard the bid and emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { @@ -441,14 +632,20 @@ class AlternateBidderCodeSpec extends BaseSpec { def defaultAccountConfig = AccountConfig.defaultAccountConfig.tap { alternateBidderCodes = new AlternateBidderCodes().tap { it.enabled = true - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: allowedBidderCodes)] + it.bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] } } - def pbsService = pbsServiceFactory.getService( + def pbsService = pbsServiceFactory.getService(AMX_CONFIG + ["settings.default-account-config": encode(defaultAccountConfig)]) and: "Default bid request" - def bidRequest = BidRequest.getDefaultBidRequest() + def bidRequest = bidRequestWithAmxBidder() + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: allowedBidderCodes) + } + bidder.setResponse(bidRequest.id, bidResponse) and: "Flash metrics" flushMetrics(pbsService) @@ -456,75 +653,65 @@ class AlternateBidderCodeSpec extends BaseSpec { when: "PBS processes auction request" def response = pbsService.sendAuctionRequest(bidRequest) - then: "Response shouldn't contain seat bid" - assert !response.seatbid - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() - and: "Response should contain warnings" - assert response.ext?.warnings[PREBID]*.code == [999] - assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 - and: "Alert.general metric should be updated" - def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[ALERT_GENERAL] + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL - where: - allowedBidderCodes << [[BOGUS], [BOGUS, UNKNOWN]] - } + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${allowedBidderCodes} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" - def "PBS should discard bid and not emit a response warning when requested alternate bidder codes are enabled and the allowed bidder code does match with alias of specified bidders"() { - given: "Default bid request with alias and alternate bidder code" - def bidRequest = bidRequestWithAlternateBidderCode().tap { - ext.prebid.aliases = [(ALIAS.value): GENERIC] - ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [UNKNOWN])] - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.generic = null - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) + and: "PBS should emit logs" + def logs = pbsService.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${allowedBidderCodes} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") - then: "Resolved request should contain aliases as in request" - assert response.ext.debug.resolvedRequest.ext.prebid.aliases == bidRequest.ext.prebid.aliases - - and: "Response shouldn't contain seat bid" - assert !response.seatbid + and: "PBS should emit metrics" + def metrics = pbsService.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - and: "Response should contain warnings" - assert response.ext?.warnings[PREBID]*.code == [999] - assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE] - - and: "Alert.general metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[ALERT_GENERAL] + where: + allowedBidderCodes << [BOGUS, UNKNOWN] } - //todo: ADD test for it, if pubmatic bidder will be updated with logic for different seat name - // check for the existence of the seat-defined-bidderCode in the bidadjustmentfactors object. If it exists, apply the adjustment and we're done. - // otherwise, check for the existence of the adaptercode (seatbid.bid.ext.prebid.meta.adaptercode) in the bidadjustmentfactors object. If it exists, apply the adjustment - private static Account accountWithAlternateBidderCode(BidRequest bidRequest) { new Account().tap { it.uuid = bidRequest.accountId it.config = new AccountConfig(status: ACTIVE) it.config = new AccountConfig(alternateBidderCodes: new AlternateBidderCodes().tap { it.enabled = true - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + it.bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] }) } } - private static BidRequest bidRequestWithAlternateBidderCode() { - BidRequest.defaultBidRequest.tap { + private static BidRequest bidRequestWithAmxBidderAndAlternateBidderCode() { + bidRequestWithAmxBidder().tap { it.ext.prebid.alternateBidderCodes = new AlternateBidderCodes().tap { - it.enabled = true - it.bidders = [(GENERIC): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + enabled = true + bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] + } + } + } + + private static BidRequest bidRequestWithAmxBidder() { + BidRequest.defaultBidRequest.tap { + it.imp[0].ext.prebid.bidder.tap { + generic = null + amx = new Amx() } + ext.prebid.returnAllBidStatus = true } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy index 79eb960787f..5155bee6bca 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy @@ -3,10 +3,13 @@ package org.prebid.server.functional.tests import org.prebid.server.functional.model.Currency import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AlternateBidderCodes +import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.mock.services.currencyconversion.CurrencyConversionRatesResponse import org.prebid.server.functional.model.request.auction.AdjustmentRule import org.prebid.server.functional.model.request.auction.AdjustmentType +import org.prebid.server.functional.model.request.auction.Amx import org.prebid.server.functional.model.request.auction.BidAdjustment import org.prebid.server.functional.model.request.auction.BidAdjustmentFactors import org.prebid.server.functional.model.request.auction.BidAdjustmentRule @@ -14,6 +17,7 @@ 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.VideoPlacementSubtypes import org.prebid.server.functional.model.request.auction.VideoPlcmtSubtype +import org.prebid.server.functional.model.response.auction.BidExt import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService @@ -27,6 +31,7 @@ import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.GBP import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.RUBICON @@ -68,7 +73,9 @@ class BidAdjustmentSpec extends BaseSpec { private static final CurrencyConversion currencyConversion = new CurrencyConversion(networkServiceContainer).tap { setCurrencyConversionRatesResponse(CurrencyConversionRatesResponse.getDefaultCurrencyConversionRatesResponse(DEFAULT_CURRENCY_RATES)) } - private static final PrebidServerService pbsService = pbsServiceFactory.getService(externalCurrencyConverterConfig) + private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + private static final PrebidServerService pbsService = pbsServiceFactory.getService(externalCurrencyConverterConfig + AMX_CONFIG) def "PBS should adjust bid price for matching bidder when request has per-bidder bid adjustment factors"() { given: "Default bid request with bid adjustment" @@ -1074,6 +1081,73 @@ class BidAdjustmentSpec extends BaseSpec { adjustmentType << [CPM, STATIC] } + def "PBS should adjust bid price for matching bidder and alternate bidder code when request has per-bidder bid adjustment factors"() { + given: "Default bid request with bid adjustment and amx bidder" + def bidRequest = BidRequest.getDefaultBidRequest(SITE).tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.amx = new Amx() + it.ext.prebid.tap { + alternateBidderCodes = new AlternateBidderCodes().tap { + enabled = true + bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } + bidAdjustmentFactors = new BidAdjustmentFactors(adjustments: [(GENERIC): bidAdjustmentFactor]) + } + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Final bid price should be adjusted" + assert response?.seatbid?.first?.bid?.first?.price == bidResponse.seatbid.first.bid.first.price * + bidAdjustmentFactor + + where: + bidAdjustmentFactor << [0.9, 1.1] + } + + def "PBS should prefer bid price adjustment based on media type and alternate bidder code when request has per-media-type bid adjustment factors"() { + given: "Default bid request with bid adjustment" + def bidAdjustment = randomDecimal + def mediaTypeBidAdjustment = bidAdjustmentFactor + def bidRequest = BidRequest.getDefaultBidRequest(SITE).tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.amx = new Amx() + ext.prebid.tap { + bidAdjustmentFactors = new BidAdjustmentFactors().tap { + adjustments = [(GENERIC): bidAdjustment] + mediaTypes = [(BANNER): [(GENERIC): mediaTypeBidAdjustment]] + } + alternateBidderCodes = new AlternateBidderCodes().tap { + enabled = true + bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } + } + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Final bid price should be adjusted" + assert response?.seatbid?.first?.bid?.first?.price == bidResponse.seatbid.first.bid.first.price * + mediaTypeBidAdjustment + + where: + bidAdjustmentFactor << [0.9, 1.1] + } + private static Map getExternalCurrencyConverterConfig() { ["auction.ad-server-currency" : DEFAULT_CURRENCY as String, "currency-converter.external-rates.enabled" : "true", 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 504a045f3ba..4b16c17c806 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -34,6 +34,7 @@ import static org.prebid.server.functional.model.Currency.CHF import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP import static org.prebid.server.functional.model.bidder.CompressionType.NONE @@ -1379,7 +1380,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC.value] and: "Bidder request should be valid" assert bidder.getBidderRequest(bidRequest.id) @@ -1399,7 +1400,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS.value] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) From b5f2f1a41501ee1ccf69b57187b84724c20e0e70 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 10 Mar 2025 12:03:32 +0200 Subject: [PATCH 07/18] Add another tests case for alternate bidder code --- .../model/config/AccountConfig.groovy | 1 + .../model/config/BidderConfig.groovy | 2 +- .../model/request/auction/Prebid.groovy | 2 +- .../tests/AlternateBidderCodeSpec.groovy | 267 +++++++++++++++--- 4 files changed, 234 insertions(+), 38 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy index e690f070db8..d2c5a64dbd6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy @@ -23,6 +23,7 @@ class AccountConfig { AccountSetting settings @JsonProperty("cookie_sync") AccountCookieSyncConfig cookieSyncSnakeCase + @JsonProperty("alternatebiddercodes") AlternateBidderCodes alternateBidderCodes static getDefaultAccountConfig() { diff --git a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy index 3ace45da056..973f9f239e6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy @@ -8,7 +8,7 @@ import org.prebid.server.functional.model.bidder.BidderName @EqualsAndHashCode @ToString(includeNames = true, ignoreNulls = true) -@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy) +@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) class BidderConfig { Boolean enabled diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index c3faf956f9f..ff139e36323 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -42,7 +42,7 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse - @JsonProperty("alternatebidderscodes") + @JsonProperty("alternatebiddercodes") AlternateBidderCodes alternateBidderCodes PaaFormat paaFormat diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 7546655480f..02b929e6671 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -1,6 +1,5 @@ package org.prebid.server.functional.tests -import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AlternateBidderCodes @@ -22,6 +21,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.AMX_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.BOGUS import static org.prebid.server.functional.model.bidder.BidderName.EMPTY +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD @@ -33,15 +33,91 @@ class AlternateBidderCodeSpec extends BaseSpec { private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - @Shared - PrebidServerService pbsServiceWithAmxBidder = pbsServiceFactory.getService(AMX_CONFIG) + private static final PrebidServerService pbsServiceWithAmxBidder = pbsServiceFactory.getService(AMX_CONFIG) @Override def cleanupSpec() { pbsServiceFactory.removeContainer(AMX_CONFIG) } + def "PBS should populate meta demand source when bid response with demand source"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder() + + and: "Bid response with demand source" + def demandSource = PBSUtils.getRandomString() + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(demandSource: demandSource) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain exp data" + assert response.seatbid.seat == [AMX] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain demand source" + assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + } + + def "PBS shouldn't populate meta demand source when bid response without demand source"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder() + + and: "Bid response without demand source" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(demandSource: null) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain exp data" + assert response.seatbid.seat == [AMX] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + } + def "PBS shouldn't discard bid for amx bidder same seat in response as seat in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" def bidRequest = bidRequestWithAmxBidder() @@ -59,7 +135,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) then: "Bid response should contain exp data" - assert response.seatbid.seat == [AMX] + assert response.seatbid.seat == [bidderCode] and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] @@ -201,7 +277,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) then: "Bid response should contain exp data" - assert response.seatbid.seat == [ALIAS] + assert response.seatbid.seat == [bidderCode] and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] @@ -298,6 +374,59 @@ class AlternateBidderCodeSpec extends BaseSpec { null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) } + def "PBS should take precede of request and discard the bid and emit a response error when alternate bidder codes enabled and bidder came with different bidder code"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + setAccountId(PBSUtils.randomString) + } + + and: "Save account config into DB with alternate bidder codes" + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes.bidders[AMX].allowedBidderCodes = [UNKNOWN] + } + accountDao.save(account) + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: UNKNOWN) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response shouldn't seat bid" + assert response.seatbid.isEmpty() + + and: "Response should seatNon bid with code 300" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == AMX.value + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_GENERAL + + and: "Response should contain error" + def error = response.ext?.errors[ErrorType.AMX][0] + assert error.code == 5 + assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + + "Error: invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + + and: "PBS should emit logs" + def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) + assert logs.contains("invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + + and: "PBS should emit metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert metrics["adapter.${AMX}.response.validation.seat"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + def "PBS should discard the bid and emit a response warning when alternate bidder codes disabled and bidder came with different bidderCode"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -353,15 +482,15 @@ class AlternateBidderCodeSpec extends BaseSpec { where: requestedAlternateBidderCodes | accountAlternateBidderCodes + false | true false | false false | null null | false } - def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { + def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodes = requestedAllowedBidderCodes + def bidRequest = bidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -373,7 +502,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { - it.seatbid[0].bid[0].ext = new BidExt(bidderCode: AMX) + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) } bidder.setResponse(bidRequest.id, bidResponse) @@ -387,7 +516,48 @@ class AlternateBidderCodeSpec extends BaseSpec { assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [AMX] + assert response.seatbid.seat.flatten() == [GENERIC] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and errors and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBs metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + + where: + accountAllowedBidderCodes << [[WILDCARD], [WILDCARD, EMPTY], [EMPTY, WILDCARD], null] + } + + def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodes = requestedAllowedBidderCodes + setAccountId(PBSUtils.randomString) + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seatbid.seat" + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -402,29 +572,59 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !metrics["adapter.${AMX}.response.validation.seat"] where: - requestedAllowedBidderCodes | accountAllowedBidderCodes - [] | null - null | [] - [WILDCARD] | null - [WILDCARD, EMPTY] | null - [WILDCARD, EMPTY] | [WILDCARD, EMPTY] - null | [WILDCARD] - null | [WILDCARD, EMPTY] - null | null - [WILDCARD] | [WILDCARD] - [] | [] - [EMPTY] | [EMPTY] - [EMPTY] | null - null | [EMPTY] + requestedAllowedBidderCodes << [[WILDCARD], [WILDCARD, EMPTY], [EMPTY, WILDCARD], null] } - def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { + def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders = requestAlternateBidders setAccountId(PBSUtils.randomString) } + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seatbid.seat" + assert response.seatbid.seat.flatten() == [GENERIC] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and errors and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBs metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + + where: + requestAlternateBidders << [[(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])], + [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])], + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])], + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]] + } + + def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAmxBidder().tap { + setAccountId(PBSUtils.randomString) + } + and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes.bidders = accountAlternateBidders @@ -433,7 +633,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { - it.seatbid[0].bid[0].ext = new BidExt(bidderCode: BidderName.GENERIC) + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) } bidder.setResponse(bidRequest.id, bidResponse) @@ -447,7 +647,7 @@ class AlternateBidderCodeSpec extends BaseSpec { assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain seatbid.seat" - assert response.seatbid.seat.flatten() == [BidderName.GENERIC] + assert response.seatbid.seat.flatten() == [GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -462,15 +662,10 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !metrics["adapter.${AMX}.response.validation.seat"] where: - accountAlternateBidders | requestAlternateBidders - [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] | null - [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null - [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] | null - [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] | null - null | [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] - null | [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] - null | [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])] - null | [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [BidderName.GENERIC])] + accountAlternateBidders << [[(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])], + [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])], + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC_CAMEL_CASE])], + [(AMX_CAMEL_CASE): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]] } def "PBS shouldn't discard the bid or emit a response warning when default account alternate bidder codes are enabled and the allowed bidder codes match the bidder's request"() { From 9f7cb87a8e834e63fb9aa51bf1618342ca855942 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 12 Mar 2025 18:04:16 +0200 Subject: [PATCH 08/18] Minor update --- .../functional/model/bidder/BidderName.groovy | 2 + .../model/config/AccountConfig.groovy | 3 +- .../model/config/BidderConfig.groovy | 3 + .../model/request/auction/Bidder.groovy | 4 + .../model/request/auction/Prebid.groovy | 1 - .../model/response/auction/ErrorType.groovy | 1 + .../tests/AlternateBidderCodeSpec.groovy | 240 ++++++++++++++- .../functional/tests/BidderParamsSpec.groovy | 277 +++++++++++++++++- 8 files changed, 512 insertions(+), 19 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy index 3cd339b7378..702918fa886 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy @@ -11,6 +11,7 @@ enum BidderName { BOGUS("bogus"), ALIAS("alias"), ALIAS_CAMEL_CASE("AlIaS"), + ALIAS_UPPER_CASE("ALIAS"), GENERIC_CAMEL_CASE("GeNerIc"), GENERIC("generic"), GENER_X("gener_x"), @@ -28,6 +29,7 @@ enum BidderName { MEDIANET("medianet"), AMX("amx"), AMX_CAMEL_CASE("AmX"), + AMX_UPPER_CASE("AMX"), @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy index d2c5a64dbd6..9dded674fee 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountConfig.groovy @@ -23,8 +23,9 @@ class AccountConfig { AccountSetting settings @JsonProperty("cookie_sync") AccountCookieSyncConfig cookieSyncSnakeCase - @JsonProperty("alternatebiddercodes") AlternateBidderCodes alternateBidderCodes + @JsonProperty("alternate_bidder_codes") + AlternateBidderCodes alternateBidderCodesSnakeCase static getDefaultAccountConfig() { new AccountConfig(status: AccountStatus.ACTIVE) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy index 973f9f239e6..6e09c388e1d 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.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.EqualsAndHashCode @@ -13,4 +14,6 @@ class BidderConfig { Boolean enabled List allowedBidderCodes + @JsonProperty("allowed-bidder-codes") + List allowedBidderCodesKebabCase } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy index 05723387d5d..9c4a17ec5cf 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy @@ -12,6 +12,8 @@ import org.prebid.server.functional.model.bidder.Rubicon class Bidder { Generic alias + @JsonProperty("ALIAS") + Generic aliasUpperCase Generic generic @JsonProperty("gener_x") Generic generX @@ -27,6 +29,8 @@ class Bidder { Adrino adrino Generic nativo Amx amx + @JsonProperty("AMX") + Amx amxUpperCase static Bidder getDefaultBidder() { new Bidder().tap { diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index ff139e36323..491d4f38f4f 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -42,7 +42,6 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse - @JsonProperty("alternatebiddercodes") AlternateBidderCodes alternateBidderCodes PaaFormat paaFormat diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy index 039aa5aca2a..80f504a05ec 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy @@ -16,6 +16,7 @@ enum ErrorType { IX("ix"), OPENX("openx"), AMX("amx"), + AMX_UPPER_CASE("AMX"), @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 02b929e6671..2907a5e757b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -7,11 +7,13 @@ import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.Amx import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.Targeting 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.ErrorType import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils +import spock.lang.IgnoreRest import spock.lang.Shared import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -25,7 +27,6 @@ import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD -import static org.prebid.server.functional.model.privacy.Metric.ALERT_GENERAL import static org.prebid.server.functional.model.response.auction.BidRejectionReason.RESPONSE_REJECTED_GENERAL import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer @@ -41,6 +42,52 @@ class AlternateBidderCodeSpec extends BaseSpec { pbsServiceFactory.removeContainer(AMX_CONFIG) } + def "PBS shouldn't discard bid amx alias when soft alias request with allowed bidder code"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + ext.prebid.aliases = [(ALIAS.value): AMX] + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: ALIAS) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain seat" + assert response.seatbid.seat == [ALIAS] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${ALIAS}"] + assert targeting["hb_size_${ALIAS}"] + assert targeting["hb_bidder"] == ALIAS.value + assert targeting["hb_bidder_${ALIAS}"] == ALIAS.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${ALIAS}.response.validation.seat"] + } + def "PBS should populate meta demand source when bid response with demand source"() { given: "Default bid request with amx bidder" def bidRequest = bidRequestWithAmxBidder() @@ -58,7 +105,7 @@ class AlternateBidderCodeSpec extends BaseSpec { when: "PBS processes auction request" def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Bid response should contain exp data" + then: "Bid response should contain seat" assert response.seatbid.seat == [AMX] and: "Response should contain adapter code" @@ -96,7 +143,7 @@ class AlternateBidderCodeSpec extends BaseSpec { when: "PBS processes auction request" def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Bid response should contain exp data" + then: "Bid response should contain seat" assert response.seatbid.seat == [AMX] and: "Response should contain adapter code" @@ -134,7 +181,7 @@ class AlternateBidderCodeSpec extends BaseSpec { when: "PBS processes auction request" def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) - then: "Bid response should contain exp data" + then: "Bid response should contain seat" assert response.seatbid.seat == [bidderCode] and: "Response should contain adapter code" @@ -256,6 +303,67 @@ class AlternateBidderCodeSpec extends BaseSpec { bidderName << [BOGUS, UNKNOWN, WILDCARD] } + //todo: need confirm + @IgnoreRest + def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode and alternate bidder code allow"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + ext.prebid.aliases = [(ALIAS.value): AMX] + ext.prebid.alternateBidderCodes = requestAlternateBidderCode + } + + and: "Save account config into DB with alternate bidder codes" + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain exp data" + assert response.seatbid.seat == [GENERIC] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${ALIAS}.response.validation.seat"] + + where: + requestAlternateBidderCode | accountAlternateBidderCodes + new AlternateBidderCodes(enabled: true, bidders: [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]) | null + null | new AlternateBidderCodes(enabled: true, bidders: [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]) + } + def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" def bidRequest = bidRequestWithAmxBidder().tap { @@ -332,12 +440,14 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings" + then: "Response shouldn't contain warnings,errors and seatnonbid" assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid - and: "Alert.general metric shouldn't be updated" + and: "Metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics[ALERT_GENERAL] + assert !metrics["adapter.${AMX}.response.validation.seat"] where: requestedAlternateBidderCodes | accountAlternateBidderCodes @@ -374,6 +484,117 @@ class AlternateBidderCodeSpec extends BaseSpec { null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) } + def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured and bidder requested in uppercase"() { + given: "Default bid request with AMX bidder" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + imp[0].ext.prebid.bidder.amx = null + imp[0].ext.prebid.bidder.tap { + amxUpperCase = new Amx() + amx = null + } + setAccountId(PBSUtils.randomString) + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat == GENERIC + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + then: "Response shouldn't contain warnings,errors and seatnonbid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "Metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + + where: + accountAlternateBidderCodes << [ + new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), + new AccountConfig(alternateBidderCodes: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), + new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]))] + } + + def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured with different case"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidder().tap { + setAccountId(PBSUtils.randomString) + } + + and: "Save account config into DB with alternate bidder codes" + def account = accountWithAlternateBidderCode(bidRequest).tap { + config = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat == GENERIC + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + then: "Response shouldn't contain warnings,errors and seatnonbid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "Metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${AMX}.response.validation.seat"] + + where: + accountAlternateBidderCodes << [ + new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), + new AccountConfig(alternateBidderCodes: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), + new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]))] + } + def "PBS should take precede of request and discard the bid and emit a response error when alternate bidder codes enabled and bidder came with different bidder code"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -906,7 +1127,10 @@ class AlternateBidderCodeSpec extends BaseSpec { generic = null amx = new Amx() } - ext.prebid.returnAllBidStatus = true + ext.prebid.tap { + returnAllBidStatus = true + targeting = new Targeting() + } } } } 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 4b16c17c806..b505ad981ce 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -22,18 +22,22 @@ import org.prebid.server.functional.model.request.auction.Native import org.prebid.server.functional.model.request.auction.PrebidOptions import org.prebid.server.functional.model.request.auction.PrebidStoredRequest import org.prebid.server.functional.model.request.auction.Site +import org.prebid.server.functional.model.request.auction.Targeting import org.prebid.server.functional.model.request.vtrack.VtrackRequest import org.prebid.server.functional.model.request.vtrack.xml.Vast 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.util.PBSUtils import org.prebid.server.functional.util.privacy.CcpaConsent +import spock.lang.IgnoreRest import static org.prebid.server.functional.model.Currency.CHF import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP @@ -1028,8 +1032,8 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted not specified"() { given: "PBS with adapter configuration" def pbsConfig = [ - "adapters.generic.aliases.alias.enabled": "true", - "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), + "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": ""] def pbsService = pbsServiceFactory.getService(pbsConfig) @@ -1148,8 +1152,8 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted intersect with requested currency"() { given: "PBS with adapter configuration" def pbsConfig = [ - "adapters.generic.aliases.alias.enabled": "true", - "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), + "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${USD},${EUR}".toString()] def pbsService = pbsServiceFactory.getService(pbsConfig) @@ -1193,8 +1197,8 @@ class BidderParamsSpec extends BaseSpec { def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.aliases.bidder.meta-info.currency-accepted not intersect with requested currency"() { given: "PBS with adapter configuration" def pbsConfig = [ - "adapters.generic.aliases.alias.enabled": "true", - "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), + "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${JPY},${CHF}".toString()] def pbsService = pbsServiceFactory.getService(pbsConfig) @@ -1380,16 +1384,17 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC.value] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] and: "Bidder request should be valid" assert bidder.getBidderRequest(bidRequest.id) } - def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested alias"() { + def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested soft alias"() { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + it.ext.prebid.targeting = new Targeting() imp[0].ext.prebid.bidder.tap { generic = null alias = new Generic() @@ -1400,7 +1405,261 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS.value] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + @IgnoreRest + def "PBS should populate same code for adapter code when make call for generic hard code alias"() { + given: "PBS config with bidder" + def pbsConfig = ["adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid request with alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + @IgnoreRest + def "PBS should make call alias when hard alias specified"() { + given: "PBS config with bidder" + def pbsConfig = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid Request with generic and openx bidder within separate imps" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + @IgnoreRest + def "PBS should make call for alias when hard alias and demandSource specified"() { + given: "PBS config with bidder" + def pbsConfig = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid Request with generic and openx bidder within separate imps" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + } + + and: "Bid response with bidder code" + def demandSource = PBSUtils.randomString + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, BidderName.ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(demandSource: demandSource) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain demand source" + assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested soft alias with upper case"() { + given: "Default bid request with alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + it.ext.prebid.targeting = new Targeting() + imp[0].ext.prebid.bidder.tap { + generic = null + aliasUpperCase = new Generic() + } + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS_UPPER_CASE] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_ALIAS"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should populate targeting with bidder in camel case when bidder with camel case was requested"() { + given: "Bid request with alwaysIncludeDeals = true" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.genericCamelCase = new Generic() + it.ext.prebid.targeting = new Targeting(includeBidderKeys: false, alwaysIncludeDeals: true) + } + + and: "Bid response with 2 bids where deal bid has higher price" + def bidPrice = PBSUtils.randomPrice + def dealBidPrice = bidPrice + 1 + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid << Bid.getDefaultBid(bidRequest.imp[0]).tap { it.price = bidPrice } + seatbid[0].bid[0].dealid = PBSUtils.randomNumber + seatbid[0].bid[0].price = dealBidPrice + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_GeNerIc"] + + and: "Bid response should contain seat" + assert response.seatbid.seat == [BidderName.GENERIC_CAMEL_CASE] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + } + + def "PBS should make call for stored request alias in upper case when soft alias specified with same name but in another case strategy"() { + given: "BidRequest with stored request, without imp" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomNumber) + ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + it.ext.prebid.targeting = new Targeting() + } + + and: "Default stored request with bad bidder datatype" + def storedRequestModel = BidRequest.defaultStoredRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + aliasUpperCase = new Generic() + } + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(bidRequest, storedRequestModel) + storedRequestDao.save(storedRequest) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS_CAMEL_CASE] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should make call for alias in upper case when soft alias specified with same name but in another case strategy"() { + given: "Default bid request with soft alias and targeting" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() + imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap["hb_bidder_alias"] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) From b1b3f088dc088cd194161a19447854099ca8d74a Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 13 Mar 2025 12:12:39 +0200 Subject: [PATCH 09/18] Minor update --- .../model/config/BidderConfig.groovy | 6 +- .../model/request/auction/Prebid.groovy | 3 +- .../tests/AlternateBidderCodeSpec.groovy | 7 +-- .../functional/tests/BidderParamsSpec.groovy | 63 ++----------------- 4 files changed, 13 insertions(+), 66 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy index 6e09c388e1d..aa9488f87fa 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy @@ -9,11 +9,11 @@ import org.prebid.server.functional.model.bidder.BidderName @EqualsAndHashCode @ToString(includeNames = true, ignoreNulls = true) -@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy) class BidderConfig { Boolean enabled List allowedBidderCodes - @JsonProperty("allowed-bidder-codes") - List allowedBidderCodesKebabCase + @JsonProperty("allowedbiddercodes") + List allowedBidderCodesLowerCase } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index 491d4f38f4f..499dccea5a3 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -42,8 +42,9 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse - AlternateBidderCodes alternateBidderCodes PaaFormat paaFormat + @JsonProperty("alternatebiddercodes") + AlternateBidderCodes alternateBidderCodes static class Channel { diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 2907a5e757b..c5a7302863c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -304,7 +304,6 @@ class AlternateBidderCodeSpec extends BaseSpec { } //todo: need confirm - @IgnoreRest def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode and alternate bidder code allow"() { given: "Default bid request with amx bidder" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -406,6 +405,7 @@ class AlternateBidderCodeSpec extends BaseSpec { bidderCode << [ALIAS, ALIAS_CAMEL_CASE] } + @IgnoreRest def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -451,7 +451,6 @@ class AlternateBidderCodeSpec extends BaseSpec { where: requestedAlternateBidderCodes | accountAlternateBidderCodes - null | null new AlternateBidderCodes() | null null | new AlternateBidderCodes() new AlternateBidderCodes(enabled: true) | null @@ -758,7 +757,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodes = requestedAllowedBidderCodes + ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodesLowerCase = requestedAllowedBidderCodes setAccountId(PBSUtils.randomString) } @@ -1116,7 +1115,7 @@ class AlternateBidderCodeSpec extends BaseSpec { bidRequestWithAmxBidder().tap { it.ext.prebid.alternateBidderCodes = new AlternateBidderCodes().tap { enabled = true - bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] + bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodesLowerCase: [AMX])] } } } 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 b505ad981ce..bf0865808ba 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -31,13 +31,11 @@ import org.prebid.server.functional.model.response.auction.BidExt import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.CcpaConsent -import spock.lang.IgnoreRest import static org.prebid.server.functional.model.Currency.CHF import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD -import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP @@ -1418,7 +1416,6 @@ class BidderParamsSpec extends BaseSpec { assert bidder.getBidderRequests(bidRequest.id) } - @IgnoreRest def "PBS should populate same code for adapter code when make call for generic hard code alias"() { given: "PBS config with bidder" def pbsConfig = ["adapters.generic.aliases.alias.enabled" : "true", @@ -1454,45 +1451,6 @@ class BidderParamsSpec extends BaseSpec { pbsServiceFactory.removeContainer(pbsConfig) } - @IgnoreRest - def "PBS should make call alias when hard alias specified"() { - given: "PBS config with bidder" - def pbsConfig = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.amx.aliases.alias.enabled" : "true", - "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid Request with generic and openx bidder within separate imps" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - generic = null - alias = new Generic() - } - ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - @IgnoreRest def "PBS should make call for alias when hard alias and demandSource specified"() { given: "PBS config with bidder" def pbsConfig = ["adapters.amx.enabled" : "true", @@ -1524,7 +1482,7 @@ class BidderParamsSpec extends BaseSpec { assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] @@ -1569,25 +1527,13 @@ class BidderParamsSpec extends BaseSpec { } def "PBS should populate targeting with bidder in camel case when bidder with camel case was requested"() { - given: "Bid request with alwaysIncludeDeals = true" + given: "Default bid request" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.generic = null imp[0].ext.prebid.bidder.genericCamelCase = new Generic() - it.ext.prebid.targeting = new Targeting(includeBidderKeys: false, alwaysIncludeDeals: true) - } - - and: "Bid response with 2 bids where deal bid has higher price" - def bidPrice = PBSUtils.randomPrice - def dealBidPrice = bidPrice + 1 - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { - seatbid[0].bid << Bid.getDefaultBid(bidRequest.imp[0]).tap { it.price = bidPrice } - seatbid[0].bid[0].dealid = PBSUtils.randomNumber - seatbid[0].bid[0].price = dealBidPrice + it.ext.prebid.targeting = new Targeting() } - and: "Set bidder response" - bidder.setResponse(bidRequest.id, bidResponse) - when: "PBS processes auction request" def response = defaultPbsService.sendAuctionRequest(bidRequest) @@ -1598,6 +1544,7 @@ class BidderParamsSpec extends BaseSpec { and: "Bid response should contain seat" assert response.seatbid.seat == [BidderName.GENERIC_CAMEL_CASE] + //adapter code should be just a generic and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] } @@ -1652,7 +1599,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] From 8802e2f58e0e55dc9b9411723c3ab208ec28b2d9 Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 13 Mar 2025 14:59:57 +0200 Subject: [PATCH 10/18] Minor update --- .../model/config/BidderConfig.groovy | 2 ++ .../tests/AlternateBidderCodeSpec.groovy | 31 +++++++------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy index aa9488f87fa..e139419e4e3 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/BidderConfig.groovy @@ -16,4 +16,6 @@ class BidderConfig { List allowedBidderCodes @JsonProperty("allowedbiddercodes") List allowedBidderCodesLowerCase + @JsonProperty("allowed_bidder_codes") + List allowedBidderCodesSnakeCase } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index c5a7302863c..7ea79df16d7 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -13,7 +13,6 @@ import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils -import spock.lang.IgnoreRest import spock.lang.Shared import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -319,7 +318,6 @@ class AlternateBidderCodeSpec extends BaseSpec { } accountDao.save(account) - and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) @@ -405,7 +403,6 @@ class AlternateBidderCodeSpec extends BaseSpec { bidderCode << [ALIAS, ALIAS_CAMEL_CASE] } - @IgnoreRest def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -486,11 +483,11 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured and bidder requested in uppercase"() { given: "Default bid request with AMX bidder" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { - imp[0].ext.prebid.bidder.amx = null imp[0].ext.prebid.bidder.tap { amxUpperCase = new Amx() amx = null } + ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodesLowerCase = [GENERIC] setAccountId(PBSUtils.randomString) } @@ -530,12 +527,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() assert !metrics["adapter.${AMX}.response.validation.seat"] - - where: - accountAlternateBidderCodes << [ - new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), - new AccountConfig(alternateBidderCodes: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), - new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]))] + assert !metrics["adapter.${GENERIC}.response.validation.seat"] } def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured with different case"() { @@ -546,7 +538,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { - config = accountAlternateBidderCodes + config = configAccountAlternateBidderCodes } accountDao.save(account) @@ -570,10 +562,10 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${AMX}"] - assert targeting["hb_size_${AMX}"] - assert targeting["hb_bidder"] == AMX.value - assert targeting["hb_bidder_${AMX}"] == AMX.value + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -588,9 +580,9 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !metrics["adapter.${AMX}.response.validation.seat"] where: - accountAlternateBidderCodes << [ - new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), - new AccountConfig(alternateBidderCodes: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesKebabCase: [GENERIC])])), + configAccountAlternateBidderCodes << [ + new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesSnakeCase: [GENERIC])])), + new AccountConfig(alternateBidderCodes: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodesSnakeCase: [GENERIC])])), new AccountConfig(alternateBidderCodesSnakeCase: new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]))] } @@ -1103,8 +1095,7 @@ class AlternateBidderCodeSpec extends BaseSpec { private static Account accountWithAlternateBidderCode(BidRequest bidRequest) { new Account().tap { it.uuid = bidRequest.accountId - it.config = new AccountConfig(status: ACTIVE) - it.config = new AccountConfig(alternateBidderCodes: new AlternateBidderCodes().tap { + it.config = new AccountConfig(status: ACTIVE, alternateBidderCodes: new AlternateBidderCodes().tap { it.enabled = true it.bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] }) From 806758f904179704c897b747b4ec82ed2fd4c9cb Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 13 Mar 2025 18:04:04 +0200 Subject: [PATCH 11/18] Minor update --- .../server/functional/tests/AlternateBidderCodeSpec.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 7ea79df16d7..185e2093c01 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -65,7 +65,7 @@ class AlternateBidderCodeSpec extends BaseSpec { assert response.seatbid.seat == [ALIAS] and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting @@ -334,7 +334,7 @@ class AlternateBidderCodeSpec extends BaseSpec { assert response.seatbid.seat == [GENERIC] and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting From 30d82f1ccb3d16d002cc7796f306d6679a292ec1 Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 14 Mar 2025 18:04:20 +0200 Subject: [PATCH 12/18] Minor update --- .../tests/AlternateBidderCodeSpec.groovy | 223 +++++++++++++++++- .../functional/tests/BidderParamsSpec.groovy | 196 +++++++++++---- 2 files changed, 370 insertions(+), 49 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 185e2093c01..fb2e45341a3 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -113,6 +113,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain demand source" assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -151,6 +158,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response shouldn't contain demand source" assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -186,6 +200,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${bidderCode}"] + assert targeting["hb_size_${bidderCode}"] + assert targeting["hb_bidder"] == bidderCode.value + assert targeting["hb_bidder_${bidderCode}"] == bidderCode.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -302,7 +323,6 @@ class AlternateBidderCodeSpec extends BaseSpec { bidderName << [BOGUS, UNKNOWN, WILDCARD] } - //todo: need confirm def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode and alternate bidder code allow"() { given: "Default bid request with amx bidder" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { @@ -387,6 +407,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${bidderCode}"] + assert targeting["hb_size_${bidderCode}"] + assert targeting["hb_bidder"] == bidderCode.value + assert targeting["hb_bidder_${bidderCode}"] == bidderCode.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -397,7 +424,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${ALIAS}.response.validation.seat"] + assert !metrics["adapter.${bidderCode}.response.validation.seat"] where: bidderCode << [ALIAS, ALIAS_CAMEL_CASE] @@ -434,6 +461,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid[0].seat == AMX + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -730,6 +764,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -771,6 +812,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -812,6 +860,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -864,6 +919,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + and: "Response shouldn't contain warnings and errors and seatNonBid" assert !response.ext?.warnings assert !response.ext?.errors @@ -914,6 +976,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [AMX] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1092,6 +1161,156 @@ class AlternateBidderCodeSpec extends BaseSpec { allowedBidderCodes << [BOGUS, UNKNOWN] } + def "PBS shouldn't discard bid when hard alias and alternate bidder allow bidder code"() { + given: "PBS config with bidder" + def pbsConfig = AMX_CONFIG + ["adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid request with alias" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + imp[0].ext.prebid.bidder.tap { + amx = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [GENERIC] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS shouldn't discard bid when alternate bidder code allow and soft alias with case"() { + given: "Default bid request with amx bidder" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() + imp[0].ext.prebid.bidder.amx = null + ext.prebid.aliases = [(ALIAS.value): AMX] + ext.prebid.alternateBidderCodes = requestAlternateBidderCode + } + + and: "Save account config into DB with alternate bidder codes" + def account = accountWithAlternateBidderCode(bidRequest).tap { + config.alternateBidderCodes = accountAlternateBidderCodes + } + accountDao.save(account) + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Bid response should contain exp data" + assert response.seatbid.seat == [GENERIC] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings and error and seatNonBid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "PBS shouldn't emit validation metrics" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics["adapter.${ALIAS}.response.validation.seat"] + assert !metrics["adapter.${GENERIC}.response.validation.seat"] + assert !metrics["adapter.${AMX}.response.validation.seat"] + + where: + requestAlternateBidderCode | accountAlternateBidderCodes + new AlternateBidderCodes(enabled: true, bidders: [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]) | null + null | new AlternateBidderCodes(enabled: true, bidders: [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])]) + } + + def "PBS should populate adapter code with requested bidder when conflict soft and hard alias and alternate bidder code"() { + given: "PBS config with bidder" + def pbsConfig = AMX_CONFIG + ["adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Bid request with amx bidder and targeting" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.aliases = [(ALIAS.value): GENERIC] + it.ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodesLowerCase: [GENERIC])] + it.ext.prebid.targeting = new Targeting() + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: GENERIC) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [GENERIC] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC}"] + assert targeting["hb_size_${GENERIC}"] + assert targeting["hb_bidder"] == GENERIC.value + assert targeting["hb_bidder_${GENERIC}"] == GENERIC.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + private static Account accountWithAlternateBidderCode(BidRequest bidRequest) { new Account().tap { it.uuid = bidRequest.accountId 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 bf0865808ba..5269d31b977 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -7,6 +7,7 @@ import org.prebid.server.functional.model.db.StoredImp import org.prebid.server.functional.model.db.StoredRequest import org.prebid.server.functional.model.request.amp.AmpRequest import org.prebid.server.functional.model.request.auction.Adrino +import org.prebid.server.functional.model.request.auction.Amx import org.prebid.server.functional.model.request.auction.AuctionEnvironment import org.prebid.server.functional.model.request.auction.Banner import org.prebid.server.functional.model.request.auction.BidRequest @@ -36,7 +37,11 @@ import static org.prebid.server.functional.model.Currency.CHF import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_UPPER_CASE +import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP import static org.prebid.server.functional.model.bidder.CompressionType.NONE @@ -1391,12 +1396,12 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested soft alias"() { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - it.ext.prebid.targeting = new Targeting() imp[0].ext.prebid.bidder.tap { generic = null alias = new Generic() } + ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + ext.prebid.targeting = new Targeting() } when: "PBS processes auction request" @@ -1408,9 +1413,12 @@ class BidderParamsSpec extends BaseSpec { and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1440,9 +1448,12 @@ class BidderParamsSpec extends BaseSpec { and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1487,9 +1498,12 @@ class BidderParamsSpec extends BaseSpec { and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1502,7 +1516,7 @@ class BidderParamsSpec extends BaseSpec { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - it.ext.prebid.targeting = new Targeting() + ext.prebid.targeting = new Targeting() imp[0].ext.prebid.bidder.tap { generic = null aliasUpperCase = new Generic() @@ -1516,11 +1530,14 @@ class BidderParamsSpec extends BaseSpec { assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS_UPPER_CASE] + assert response.seatbid.seat == [ALIAS_UPPER_CASE] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_ALIAS"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${ALIAS_UPPER_CASE}"] + assert targeting["hb_size_${ALIAS_UPPER_CASE}"] + assert targeting["hb_bidder"] == ALIAS_UPPER_CASE.value + assert targeting["hb_bidder_${ALIAS_UPPER_CASE}"] == ALIAS_UPPER_CASE.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1537,61 +1554,103 @@ class BidderParamsSpec extends BaseSpec { when: "PBS processes auction request" def response = defaultPbsService.sendAuctionRequest(bidRequest) - then: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_GeNerIc"] + then: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC_CAMEL_CASE}"] + assert targeting["hb_size_${GENERIC_CAMEL_CASE}"] + assert targeting["hb_bidder"] == GENERIC_CAMEL_CASE.value + assert targeting["hb_bidder_${GENERIC_CAMEL_CASE}"] == GENERIC_CAMEL_CASE.value and: "Bid response should contain seat" - assert response.seatbid.seat == [BidderName.GENERIC_CAMEL_CASE] + assert response.seatbid.seat == [GENERIC_CAMEL_CASE] - //adapter code should be just a generic and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] } - def "PBS should make call for stored request alias in upper case when soft alias specified with same name but in another case strategy"() { - given: "BidRequest with stored request, without imp" + def "PBS should make call for alias in upper case when soft alias specified with same name in upper case strategy"() { + given: "Default bid request with soft alias and targeting" def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomNumber) ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() + imp[0].ext.prebid.bidder.generic = null it.ext.prebid.targeting = new Targeting() } - and: "Default stored request with bad bidder datatype" - def storedRequestModel = BidRequest.defaultStoredRequest.tap { - imp[0].ext.prebid.bidder.tap { - generic = null - aliasUpperCase = new Generic() - } - } + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) - and: "Save storedRequest into DB" - def storedRequest = StoredRequest.getStoredRequest(bidRequest, storedRequestModel) - storedRequestDao.save(storedRequest) + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [ALIAS_UPPER_CASE] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${ALIAS_UPPER_CASE}"] + assert targeting["hb_size_${ALIAS_UPPER_CASE}"] + assert targeting["hb_bidder"] == ALIAS_UPPER_CASE.value + assert targeting["hb_bidder_${ALIAS_UPPER_CASE}"] == ALIAS_UPPER_CASE.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should populate adapter code with requested bidder when conflict with soft and hard alias"() { + given: "PBS config with bidder" + def pbsConfig = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Bid request with amx bidder and targeting" + def bidRequest = BidRequest.getDefaultBidRequest().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] + it.ext.prebid.targeting = new Targeting() + } when: "PBS processes auction request" def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS_CAMEL_CASE] + assert response.seatbid.seat == [BidderName.ALIAS] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } - def "PBS should make call for alias in upper case when soft alias specified with same name but in another case strategy"() { - given: "Default bid request with soft alias and targeting" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() + def "PBS should populate adapter code with requested bidder when conflict with soft and generic hard alias"() { + given: "PBS config with bidders" + def pbsConfig = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Bid request with amx bidder and targeting" + def bidRequest = BidRequest.getDefaultBidRequest().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.aliases = [(ALIAS.value): AMX] it.ext.prebid.targeting = new Targeting() } @@ -1604,11 +1663,54 @@ class BidderParamsSpec extends BaseSpec { and: "Response should contain seat bid" assert response.seatbid.seat == [BidderName.ALIAS] - and: "PBS response targeting contains bidder specific keys" - def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting - assert targetingKeyMap["hb_bidder_alias"] + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS should properly populate bidder code when soft alias ignore standalone adapter"() { + given: "PBS config with amx bidder" + def pbsConfig = ["adapters.amx.enabled" : "true", + "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid request with soft alias and targeting" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.amx = new Amx() + imp[0].ext.prebid.bidder.generic = null + ext.prebid.targeting = new Targeting() + ext.prebid.aliases = [(AMX.value): BidderName.GENERIC] + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seat" + assert response.seatbid.seat == [AMX] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } } From 8db70a73b63131a39164f6fb38e362de2884c33e Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 18 Mar 2025 14:23:14 +0200 Subject: [PATCH 13/18] Update after review --- .../model/bidder/GeneralBidderAdapter.groovy | 8 +- .../server/functional/tests/AliasSpec.groovy | 6 +- .../tests/AlternateBidderCodeSpec.groovy | 288 ++++++++++++------ .../ResponseCorrectionSpec.groovy | 4 +- 4 files changed, 208 insertions(+), 98 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy index 50d4f960327..b583363974c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy @@ -1,10 +1,14 @@ package org.prebid.server.functional.model.bidder +import com.fasterxml.jackson.annotation.JsonProperty + class GeneralBidderAdapter extends Generic { String siteId List size String sid - String ds - String bc + @JsonProperty("ds") + String demandSource + @JsonProperty("bc") + BidderName bidderCode } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy index 4e544498f44..9013978f76f 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy @@ -110,7 +110,7 @@ class AliasSpec extends BaseSpec { then: "Request should fail with error" def exception = thrown(PrebidServerException) assert exception.responseBody.contains("Invalid request format: request.ext.prebid.aliasgvlids. " + - "vendorId ${validId} refers to unknown bidder alias: ${bidderName}") + "vendorId ${validId} refers to unknown bidder alias: ${bidderName.toLowerCase()}") } def "PBS should return an error when GVL ID alias value is lower that one"() { @@ -126,7 +126,7 @@ class AliasSpec extends BaseSpec { then: "Request should fail with error" def exception = thrown(PrebidServerException) assert exception.responseBody.contains("Invalid request format: request.ext.prebid.aliasgvlids. " + - "Invalid vendorId ${invalidId} for alias: ${bidderName}. Choose a different vendorId, or remove this entry.") + "Invalid vendorId ${invalidId} for alias: ${bidderName.toLowerCase()}. Choose a different vendorId, or remove this entry.") where: invalidId << [PBSUtils.randomNegativeNumber, 0] @@ -145,7 +145,7 @@ class AliasSpec extends BaseSpec { then: "Request should fail with an error" def exception = thrown(PrebidServerException) assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: request.ext.prebid.aliases.$randomString " + + assert exception.responseBody == "Invalid request format: request.ext.prebid.aliases.${randomString.toLowerCase()} " + "refers to unknown bidder: $BOGUS.value" } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index fb2e45341a3..0163cdf0b26 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -31,6 +31,10 @@ import static org.prebid.server.functional.testcontainers.Dependencies.getNetwor class AlternateBidderCodeSpec extends BaseSpec { + private static final String ADAPTER_RESPONSE_VALIDATION_METRICS = "adapter.%s.response.validation.seat" + private static final String ERROR_BID_CODE_VALIDATION = "BidId `%s` validation messages: " + + "Error: invalid bidder code %s was set by the adapter %s for the account %s" + private static final String INVALID_BIDDER_CODE_LOGS = "invalid bidder code %s was set by the adapter %s for the account %s" private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] @Shared @@ -82,9 +86,12 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !response.ext?.errors assert !response.ext?.seatnonbid + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${ALIAS}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(ALIAS)] } def "PBS should populate meta demand source when bid response with demand source"() { @@ -130,7 +137,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] } def "PBS shouldn't populate meta demand source when bid response without demand source"() { @@ -175,7 +182,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] } def "PBS shouldn't discard bid for amx bidder same seat in response as seat in bid.ext.bidderCode"() { @@ -215,9 +222,12 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !response.ext?.errors assert !response.ext?.seatnonbid + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: bidderCode << [AMX, AMX_CAMEL_CASE] @@ -253,19 +263,19 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${bidderName} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, bidderName, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${bidderName} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(bidderName, AMX, bidRequest.accountId)) and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) and: "PBS should emit metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: bidderName << [BOGUS, UNKNOWN, WILDCARD] @@ -305,19 +315,19 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.ALIAS][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${bidderName} was set by the adapter ${ALIAS} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, bidderName, ALIAS, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${bidderName} was set by the adapter ${ALIAS} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(bidderName, ALIAS, bidRequest.accountId)) and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) and: "PBS should emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${ALIAS}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(ALIAS)] where: bidderName << [BOGUS, UNKNOWN, WILDCARD] @@ -353,6 +363,9 @@ class AlternateBidderCodeSpec extends BaseSpec { then: "Bid response should contain exp data" assert response.seatbid.seat == [GENERIC] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] @@ -373,7 +386,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${ALIAS}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(ALIAS)] where: requestAlternateBidderCode | accountAlternateBidderCodes @@ -407,6 +420,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting assert targeting["hb_pb_${bidderCode}"] @@ -424,16 +440,15 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${bidderCode}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(bidderCode)] where: bidderCode << [ALIAS, ALIAS_CAMEL_CASE] } - def "PBS shouldn't discard the bid or emit a response warning when alternate bidder codes not fully configured"() { + def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { - ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + def bidRequest = bidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -471,47 +486,100 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings,errors and seatnonbid" + and: "Response shouldn't contain warnings,errors and seatnonbid" assert !response.ext?.warnings assert !response.ext?.errors assert !response.ext?.seatnonbid + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: - requestedAlternateBidderCodes | accountAlternateBidderCodes - new AlternateBidderCodes() | null - null | new AlternateBidderCodes() - new AlternateBidderCodes(enabled: true) | null - new AlternateBidderCodes(enabled: false) | null - null | new AlternateBidderCodes(enabled: true) - null | new AlternateBidderCodes(enabled: false) - new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]) | null - new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) | null - new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]) | null - null | new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]) - null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]) - null | new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]) - new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null - new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null - new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) | null - new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) | null - null | new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) - null | new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) - null | new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]) - null | new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]) + accountAlternateBidderCodes << [null, + new AlternateBidderCodes(), + new AlternateBidderCodes(enabled: true), + new AlternateBidderCodes(enabled: false), + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]), + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]), + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])])] + } + + def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes not fully configured"() { + given: "Default bid request with alternate bidder codes" + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes + } + + and: "Bid response with bidder code" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { + it.seatbid[0].bid[0].ext = new BidExt(bidderCode: AMX) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flash metrics" + flushMetrics(pbsServiceWithAmxBidder) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seatbid.seat" + assert response.seatbid[0].seat == AMX + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain warnings,errors and seatnonbid" + assert !response.ext?.warnings + assert !response.ext?.errors + assert !response.ext?.seatnonbid + + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + + and: "Metric shouldn't be updated" + def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] + + where: + requestedAlternateBidderCodes << [null, + new AlternateBidderCodes(), + new AlternateBidderCodes(enabled: true), + new AlternateBidderCodes(enabled: false), + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig()]), + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig()]), + new AlternateBidderCodes(bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]), + new AlternateBidderCodes(enabled: false, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(enabled: false, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])]), + new AlternateBidderCodes(enabled: true, bidders: [(AMX): new BidderConfig(enabled: false, allowedBidderCodes: [UNKNOWN])]), + new AlternateBidderCodes(enabled: true, bidders: [(UNKNOWN): new BidderConfig(enabled: false, allowedBidderCodes: [AMX])])] } def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured and bidder requested in uppercase"() { @@ -522,7 +590,6 @@ class AlternateBidderCodeSpec extends BaseSpec { amx = null } ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodesLowerCase = [GENERIC] - setAccountId(PBSUtils.randomString) } and: "Bid response with bidder code" @@ -553,15 +620,17 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings,errors and seatnonbid" + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + + and: "Response shouldn't contain warnings,errors and seatnonbid" assert !response.ext?.warnings assert !response.ext?.errors assert !response.ext?.seatnonbid and: "Metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] - assert !metrics["adapter.${GENERIC}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] } def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured with different case"() { @@ -604,14 +673,17 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - then: "Response shouldn't contain warnings,errors and seatnonbid" + and: "Response shouldn't contain warnings,errors and seatnonbid" assert !response.ext?.warnings assert !response.ext?.errors assert !response.ext?.seatnonbid + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: configAccountAlternateBidderCodes << [ @@ -658,16 +730,16 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, UNKNOWN, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(UNKNOWN, AMX, bidRequest.accountId)) and: "PBS should emit metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -712,16 +784,16 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, UNKNOWN, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${UNKNOWN} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(UNKNOWN, AMX, bidRequest.accountId)) and: "PBS should emit metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -774,6 +846,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response shouldn't contain warnings and errors and seatNonBid" assert !response.ext?.warnings assert !response.ext?.errors @@ -781,7 +856,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBs metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: accountAllowedBidderCodes << [[WILDCARD], [WILDCARD, EMPTY], [EMPTY, WILDCARD], null] @@ -791,7 +866,6 @@ class AlternateBidderCodeSpec extends BaseSpec { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodesLowerCase = requestedAllowedBidderCodes - setAccountId(PBSUtils.randomString) } and: "Bid response with bidder code" @@ -827,9 +901,12 @@ class AlternateBidderCodeSpec extends BaseSpec { assert !response.ext?.errors assert !response.ext?.seatnonbid + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "PBs metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: requestedAllowedBidderCodes << [[WILDCARD], [WILDCARD, EMPTY], [EMPTY, WILDCARD], null] @@ -839,7 +916,6 @@ class AlternateBidderCodeSpec extends BaseSpec { given: "Default bid request with alternate bidder codes" def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders = requestAlternateBidders - setAccountId(PBSUtils.randomString) } and: "Bid response with bidder code" @@ -860,6 +936,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [GENERIC] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting assert targeting["hb_pb_${GENERIC}"] @@ -877,7 +956,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBs metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: requestAlternateBidders << [[(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])], @@ -919,6 +998,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting assert targeting["hb_pb_${GENERIC}"] @@ -933,7 +1015,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBs metric shouldn't be updated" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: accountAlternateBidders << [[(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])], @@ -973,6 +1055,9 @@ class AlternateBidderCodeSpec extends BaseSpec { then: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain seatbid.seat" assert response.seatbid.seat.flatten() == [AMX] @@ -993,7 +1078,7 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Alert.general metric shouldn't be updated" def metrics = pbsService.sendCollectedMetricsRequest() - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(config) @@ -1001,9 +1086,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard the bid and emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode() and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -1031,16 +1114,16 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, requestedAllowedBidderCode, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(requestedAllowedBidderCode, AMX, bidRequest.accountId)) and: "PBS should emit metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1085,16 +1168,16 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, requestedAllowedBidderCode, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsServiceWithAmxBidder.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${requestedAllowedBidderCode} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(requestedAllowedBidderCode, AMX, bidRequest.accountId)) and: "PBS should emit metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) @@ -1111,8 +1194,8 @@ class AlternateBidderCodeSpec extends BaseSpec { it.bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodes: [AMX])] } } - def pbsService = pbsServiceFactory.getService(AMX_CONFIG + - ["settings.default-account-config": encode(defaultAccountConfig)]) + def pbsConfig = AMX_CONFIG + ["settings.default-account-config": encode(defaultAccountConfig)] + def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request" def bidRequest = bidRequestWithAmxBidder() @@ -1143,20 +1226,26 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain error" def error = response.ext?.errors[ErrorType.AMX][0] assert error.code == 5 - assert error.message == "BidId `${bidResponse.seatbid[0].bid[0].id}` validation messages: " + - "Error: invalid bidder code ${allowedBidderCodes} was set by the adapter ${AMX} for the account ${bidRequest.accountId}" + assert error.message == ERROR_BID_CODE_VALIDATION + .formatted(bidResponse.seatbid[0].bid[0].id, allowedBidderCodes, AMX, bidRequest.accountId) and: "PBS should emit logs" def logs = pbsService.getLogsByValue(bidRequest.accountId) - assert logs.contains("invalid bidder code ${allowedBidderCodes} was set by the adapter ${AMX} for the account ${bidRequest.accountId}") + assert logs.contains(INVALID_BIDDER_CODE_LOGS.formatted(allowedBidderCodes, AMX, bidRequest.accountId)) + + and: "Response shouldn't contain demand source" + assert !response?.seatbid?.bid?.ext?.prebid?.meta?.demandSource and: "PBS should emit metrics" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics["adapter.${AMX}.response.validation.seat"] + assert metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + where: allowedBidderCodes << [BOGUS, UNKNOWN] } @@ -1202,6 +1291,13 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + + and: "PBS shouldn't emit validation metrics" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] + cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) } @@ -1239,6 +1335,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain adapter code" assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting assert targeting["hb_pb_${GENERIC}"] @@ -1256,9 +1355,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = pbsServiceWithAmxBidder.sendCollectedMetricsRequest() - assert !metrics["adapter.${ALIAS}.response.validation.seat"] - assert !metrics["adapter.${GENERIC}.response.validation.seat"] - assert !metrics["adapter.${AMX}.response.validation.seat"] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(ALIAS)] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] where: requestAlternateBidderCode | accountAlternateBidderCodes @@ -1297,6 +1396,9 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Response should contain seat bid" assert response.seatbid.seat == [GENERIC] + and: "Response shouldn't contain demand source" + assert !response.seatbid.first.bid.first.ext.prebid.meta.demandSource + and: "Response should contain bidder targeting" def targeting = response.seatbid[0].bid[0].ext.prebid.targeting assert targeting["hb_pb_${GENERIC}"] @@ -1307,6 +1409,10 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) + and: "PBS shouldn't emit validation metrics" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] + cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) } 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..b4cbdd3fb88 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 @@ -233,7 +233,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { assert response.seatbid.bid.ext.prebid.type.flatten() == [mediaType] and: "Response shouldn't contain media type for prebid meta" - assert !response?.seatbid?.bid?.ext?.prebid?.meta?.mediaType?.flatten()?.size() + assert !response?.seatbid?.first?.bid?.first?.ext?.prebid?.meta?.mediaType and: "Response shouldn't contain errors" assert !response.ext.errors @@ -516,7 +516,7 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { assert response.seatbid.bid.ext.prebid.type.flatten() == [VIDEO] and: "Response shouldn't contain media type for prebid meta" - assert !response?.seatbid?.bid?.ext?.prebid?.meta?.mediaType?.flatten()?.size() + assert !response?.seatbid?.first?.bid?.first?.ext?.prebid?.meta?.mediaType and: "Response shouldn't contain errors" assert !response.ext.errors From 04c052603cf3043893fbf5a71d496c6c3c3f4c4e Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 19 Mar 2025 11:49:09 +0200 Subject: [PATCH 14/18] Update after review --- .../tests/AlternateBidderCodeSpec.groovy | 58 +++++++++---------- .../functional/tests/BidAdjustmentSpec.groovy | 3 +- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 0163cdf0b26..1e089def570 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -47,7 +47,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid amx alias when soft alias request with allowed bidder code"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { imp[0].ext.prebid.bidder.alias = new Generic() imp[0].ext.prebid.bidder.amx = null ext.prebid.aliases = [(ALIAS.value): AMX] @@ -96,7 +96,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should populate meta demand source when bid response with demand source"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder() + def bidRequest = getBidRequestWithAmxBidder() and: "Bid response with demand source" def demandSource = PBSUtils.getRandomString() @@ -142,7 +142,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't populate meta demand source when bid response without demand source"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder() + def bidRequest = getBidRequestWithAmxBidder() and: "Bid response without demand source" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -187,7 +187,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid for amx bidder same seat in response as seat in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder() + def bidRequest = getBidRequestWithAmxBidder() and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -235,7 +235,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard bid for amx bidder when imp[].bidder isn't same as in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder() + def bidRequest = getBidRequestWithAmxBidder() and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -283,7 +283,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard bid amx alias requested when imp[].bidder isn't same as in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { imp[0].ext.prebid.bidder.alias = new Generic() imp[0].ext.prebid.bidder.amx = null ext.prebid.aliases = [(ALIAS.value): AMX] @@ -335,7 +335,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode and alternate bidder code allow"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { imp[0].ext.prebid.bidder.alias = new Generic() imp[0].ext.prebid.bidder.amx = null ext.prebid.aliases = [(ALIAS.value): AMX] @@ -396,7 +396,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid amx alias requested when imp[].bidder is same as in bid.ext.bidderCode"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { imp[0].ext.prebid.bidder.alias = new Generic() imp[0].ext.prebid.bidder.amx = null ext.prebid.aliases = [(ALIAS.value): AMX] @@ -448,7 +448,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -519,7 +519,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes = requestedAlternateBidderCodes } @@ -584,7 +584,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured and bidder requested in uppercase"() { given: "Default bid request with AMX bidder" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { imp[0].ext.prebid.bidder.tap { amxUpperCase = new Amx() amx = null @@ -635,7 +635,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured with different case"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -694,7 +694,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should take precede of request and discard the bid and emit a response error when alternate bidder codes enabled and bidder came with different bidder code"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { setAccountId(PBSUtils.randomString) } @@ -747,7 +747,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard the bid and emit a response warning when alternate bidder codes disabled and bidder came with different bidderCode"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes setAccountId(PBSUtils.randomString) } @@ -808,7 +808,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -864,7 +864,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders[AMX].allowedBidderCodesLowerCase = requestedAllowedBidderCodes } @@ -914,7 +914,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.bidders = requestAlternateBidders } @@ -967,7 +967,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -1036,7 +1036,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def pbsService = pbsServiceFactory.getService(config) and: "Default bid request" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes = null } @@ -1086,7 +1086,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard the bid and emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode() + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode() and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -1134,7 +1134,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard the bid and emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = bidRequestWithAmxBidder().tap { + def bidRequest = getBidRequestWithAmxBidder().tap { setAccountId(PBSUtils.randomString) } @@ -1198,7 +1198,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request" - def bidRequest = bidRequestWithAmxBidder() + def bidRequest = getBidRequestWithAmxBidder() and: "Bid response with bidder code" def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, AMX).tap { @@ -1257,12 +1257,11 @@ class AlternateBidderCodeSpec extends BaseSpec { def defaultPbsService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request with alias" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { imp[0].ext.prebid.bidder.tap { amx = null alias = new Generic() } - ext.prebid.targeting = new Targeting() ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodes: [GENERIC])] } @@ -1304,7 +1303,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid when alternate bidder code allow and soft alias with case"() { given: "Default bid request with amx bidder" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() imp[0].ext.prebid.bidder.amx = null ext.prebid.aliases = [(ALIAS.value): AMX] @@ -1372,13 +1371,12 @@ class AlternateBidderCodeSpec extends BaseSpec { def defaultPbsService = pbsServiceFactory.getService(pbsConfig) and: "Bid request with amx bidder and targeting" - def bidRequest = bidRequestWithAmxBidderAndAlternateBidderCode().tap { + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { imp[0].ext.prebid.bidder.alias = new Generic() imp[0].ext.prebid.bidder.amx = null imp[0].ext.prebid.bidder.generic = null it.ext.prebid.aliases = [(ALIAS.value): GENERIC] it.ext.prebid.alternateBidderCodes.bidders = [(ALIAS): new BidderConfig(enabled: true, allowedBidderCodesLowerCase: [GENERIC])] - it.ext.prebid.targeting = new Targeting() } and: "Bid response with bidder code" @@ -1427,8 +1425,8 @@ class AlternateBidderCodeSpec extends BaseSpec { } } - private static BidRequest bidRequestWithAmxBidderAndAlternateBidderCode() { - bidRequestWithAmxBidder().tap { + private static BidRequest getBidRequestWithAmxBidderAndAlternateBidderCode() { + getBidRequestWithAmxBidder().tap { it.ext.prebid.alternateBidderCodes = new AlternateBidderCodes().tap { enabled = true bidders = [(AMX): new BidderConfig(enabled: true, allowedBidderCodesLowerCase: [AMX])] @@ -1436,7 +1434,7 @@ class AlternateBidderCodeSpec extends BaseSpec { } } - private static BidRequest bidRequestWithAmxBidder() { + private static BidRequest getBidRequestWithAmxBidder() { BidRequest.defaultBidRequest.tap { it.imp[0].ext.prebid.bidder.tap { generic = null diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy index 5155bee6bca..88f74bba3c0 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy @@ -1114,14 +1114,13 @@ class BidAdjustmentSpec extends BaseSpec { def "PBS should prefer bid price adjustment based on media type and alternate bidder code when request has per-media-type bid adjustment factors"() { given: "Default bid request with bid adjustment" - def bidAdjustment = randomDecimal def mediaTypeBidAdjustment = bidAdjustmentFactor def bidRequest = BidRequest.getDefaultBidRequest(SITE).tap { imp[0].ext.prebid.bidder.generic = null imp[0].ext.prebid.bidder.amx = new Amx() ext.prebid.tap { bidAdjustmentFactors = new BidAdjustmentFactors().tap { - adjustments = [(GENERIC): bidAdjustment] + adjustments = [(GENERIC): randomDecimal] mediaTypes = [(BANNER): [(GENERIC): mediaTypeBidAdjustment]] } alternateBidderCodes = new AlternateBidderCodes().tap { From 748ece580196dfc59c8659bdf3093fa0e330de26 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 19 Mar 2025 12:12:07 +0200 Subject: [PATCH 15/18] Update after review --- .../server/functional/tests/AlternateBidderCodeSpec.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 1e089def570..1b353c72cb1 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -635,9 +635,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard bid when alternate bidder code allows bidder codes fully configured with different case"() { given: "Default bid request with amx bidder" - def bidRequest = getBidRequestWithAmxBidder().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { From dc523cea58cc875d4588c551d37ee9a093b0be21 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 19 Mar 2025 12:13:03 +0200 Subject: [PATCH 16/18] Update after review --- .../prebid/server/functional/tests/BidAdjustmentSpec.groovy | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy index 88f74bba3c0..d4fd06cad64 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy @@ -1114,14 +1114,13 @@ class BidAdjustmentSpec extends BaseSpec { def "PBS should prefer bid price adjustment based on media type and alternate bidder code when request has per-media-type bid adjustment factors"() { given: "Default bid request with bid adjustment" - def mediaTypeBidAdjustment = bidAdjustmentFactor def bidRequest = BidRequest.getDefaultBidRequest(SITE).tap { imp[0].ext.prebid.bidder.generic = null imp[0].ext.prebid.bidder.amx = new Amx() ext.prebid.tap { bidAdjustmentFactors = new BidAdjustmentFactors().tap { adjustments = [(GENERIC): randomDecimal] - mediaTypes = [(BANNER): [(GENERIC): mediaTypeBidAdjustment]] + mediaTypes = [(BANNER): [(GENERIC): bidAdjustmentFactor]] } alternateBidderCodes = new AlternateBidderCodes().tap { enabled = true @@ -1141,7 +1140,7 @@ class BidAdjustmentSpec extends BaseSpec { then: "Final bid price should be adjusted" assert response?.seatbid?.first?.bid?.first?.price == bidResponse.seatbid.first.bid.first.price * - mediaTypeBidAdjustment + bidAdjustmentFactor where: bidAdjustmentFactor << [0.9, 1.1] From 3332be4cf38539e912f34fc38768cc29b1237ac4 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 19 Mar 2025 12:20:13 +0200 Subject: [PATCH 17/18] Update after review --- .../tests/AlternateBidderCodeSpec.groovy | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 1b353c72cb1..2fcf7876d07 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -448,9 +448,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes not fully configured"() { given: "Default bid request with alternate bidder codes" - def bidRequest = getBidRequestWithAmxBidder().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { @@ -692,9 +690,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should take precede of request and discard the bid and emit a response error when alternate bidder codes enabled and bidder came with different bidder code"() { given: "Default bid request with alternate bidder codes" - def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { @@ -747,7 +743,6 @@ class AlternateBidderCodeSpec extends BaseSpec { given: "Default bid request with alternate bidder codes" def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode().tap { ext.prebid.alternateBidderCodes.enabled = requestedAlternateBidderCodes - setAccountId(PBSUtils.randomString) } and: "Save account config into DB with alternate bidder codes" @@ -806,9 +801,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and allowed bidder codes are either a wildcard or empty"() { given: "Default bid request with alternate bidder codes" - def bidRequest = getBidRequestWithAmxBidder().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { @@ -965,9 +958,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS shouldn't discard the bid or emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes is same as bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = getBidRequestWithAmxBidder().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest).tap { @@ -1132,9 +1123,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def "PBS should discard the bid and emit a response warning when account alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { given: "Default bid request with alternate bidder codes" - def bidRequest = getBidRequestWithAmxBidder().tap { - setAccountId(PBSUtils.randomString) - } + def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" def account = accountWithAlternateBidderCode(bidRequest) From 429c87f06706c0500f60ebad9b90c48e0b3f6fe4 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 19 Mar 2025 12:24:48 +0200 Subject: [PATCH 18/18] Rename method --- .../tests/AlternateBidderCodeSpec.groovy | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 2fcf7876d07..048a4983050 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -343,7 +343,7 @@ class AlternateBidderCodeSpec extends BaseSpec { } and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes = accountAlternateBidderCodes } accountDao.save(account) @@ -451,7 +451,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes = accountAlternateBidderCodes } accountDao.save(account) @@ -636,7 +636,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config = configAccountAlternateBidderCodes } accountDao.save(account) @@ -693,7 +693,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidderAndAlternateBidderCode() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes.bidders[AMX].allowedBidderCodes = [UNKNOWN] } accountDao.save(account) @@ -746,7 +746,7 @@ class AlternateBidderCodeSpec extends BaseSpec { } and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes.enabled = accountAlternateBidderCodes } accountDao.save(account) @@ -804,7 +804,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes.bidders[AMX].allowedBidderCodes = accountAllowedBidderCodes } accountDao.save(account) @@ -961,7 +961,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes.bidders = accountAlternateBidders } accountDao.save(account) @@ -1126,7 +1126,7 @@ class AlternateBidderCodeSpec extends BaseSpec { def bidRequest = getBidRequestWithAmxBidder() and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest) + def account = getAccountWithAlternateBidderCode(bidRequest) accountDao.save(account) and: "Bid response with bidder code" @@ -1298,7 +1298,7 @@ class AlternateBidderCodeSpec extends BaseSpec { } and: "Save account config into DB with alternate bidder codes" - def account = accountWithAlternateBidderCode(bidRequest).tap { + def account = getAccountWithAlternateBidderCode(bidRequest).tap { config.alternateBidderCodes = accountAlternateBidderCodes } accountDao.save(account) @@ -1402,7 +1402,7 @@ class AlternateBidderCodeSpec extends BaseSpec { pbsServiceFactory.removeContainer(pbsConfig) } - private static Account accountWithAlternateBidderCode(BidRequest bidRequest) { + private static Account getAccountWithAlternateBidderCode(BidRequest bidRequest) { new Account().tap { it.uuid = bidRequest.accountId it.config = new AccountConfig(status: ACTIVE, alternateBidderCodes: new AlternateBidderCodes().tap {