diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AppVideoHtml.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AppVideoHtml.groovy index 6486e292ed5..602893b2808 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AppVideoHtml.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AppVideoHtml.groovy @@ -1,6 +1,5 @@ package org.prebid.server.functional.model.config -import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString 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 23b4e7f87a5..4b1dacc8f8e 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 @@ -49,6 +49,8 @@ class Prebid { List profileNames @JsonProperty("kvps") Map keyValuePairs + @JsonProperty("ortberrors") + Boolean ortbErrors static class Channel { diff --git a/src/test/groovy/org/prebid/server/functional/model/response/BidderError.groovy b/src/test/groovy/org/prebid/server/functional/model/response/BidderError.groovy index 4b6c3bdd820..f1e9a2c2471 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/BidderError.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/BidderError.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.model.response +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString @@ -8,7 +9,9 @@ import groovy.transform.ToString @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy) class BidderError { - Integer code + BidderErrorCode code String message + @JsonProperty("error") + String errorMessage Set impIds } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/BidderErrorCode.groovy b/src/test/groovy/org/prebid/server/functional/model/response/BidderErrorCode.groovy new file mode 100644 index 00000000000..20363b9d8e5 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/BidderErrorCode.groovy @@ -0,0 +1,23 @@ +package org.prebid.server.functional.model.response + +import com.fasterxml.jackson.annotation.JsonValue +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +enum BidderErrorCode { + + TIMEOUT(1), + BAD_INPUT(2), + BAD_SERVER_RESPONSE(3), + FAILED_TO_REQUEST_BIDS(4), + INVALID_BID(5), + REJECTED_IPF(6), + GENERIC(999) + + @JsonValue + final Integer value + + BidderErrorCode(Integer value) { + this.value = value + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/amp/AmpResponseExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/amp/AmpResponseExt.groovy index fbb598dccba..4bfa092e481 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/amp/AmpResponseExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/amp/AmpResponseExt.groovy @@ -3,10 +3,11 @@ package org.prebid.server.functional.model.response.amp import org.prebid.server.functional.model.response.BidderError import org.prebid.server.functional.model.response.Debug import org.prebid.server.functional.model.response.auction.ErrorType +import org.prebid.server.functional.model.response.auction.WarningEntry class AmpResponseExt { Debug debug Map> errors - Map> warnings + Map> warnings } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/amp/RawAmpResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/amp/RawAmpResponse.groovy index 18e7f705a1e..21616a85f3c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/amp/RawAmpResponse.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/amp/RawAmpResponse.groovy @@ -6,5 +6,6 @@ import groovy.transform.ToString class RawAmpResponse { String responseBody + Integer statusCode Map> headers } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/RawAuctionResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/RawAuctionResponse.groovy index e9f8f01730f..fea6c0a7151 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/RawAuctionResponse.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/RawAuctionResponse.groovy @@ -7,5 +7,6 @@ import org.prebid.server.functional.model.ResponseModel class RawAuctionResponse implements ResponseModel { String responseBody + Integer statusCode Map> headers } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/WarningEntry.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/WarningEntry.groovy index 655a0743212..6de8ce6cb6c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/WarningEntry.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/WarningEntry.groovy @@ -3,12 +3,13 @@ package org.prebid.server.functional.model.response.auction import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString +import org.prebid.server.functional.model.response.BidderErrorCode @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy) class WarningEntry { - Integer code + BidderErrorCode code String message Set impIds } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/cookiesync/RawCookieSyncResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/cookiesync/RawCookieSyncResponse.groovy index 3854da82dde..030fc92dac2 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/cookiesync/RawCookieSyncResponse.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/cookiesync/RawCookieSyncResponse.groovy @@ -6,5 +6,6 @@ import groovy.transform.ToString class RawCookieSyncResponse { String responseBody + Integer statusCode Map> headers } diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 249d6fa3f13..4a1dc4aaafd 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -43,9 +43,9 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC +import static org.apache.http.HttpStatus.SC_OK import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer - class PrebidServerService implements ObjectMapperWrapper { static final String AUCTION_ENDPOINT = "/openrtb2/auction" @@ -86,10 +86,14 @@ class PrebidServerService implements ObjectMapperWrapper { prometheusRequestSpecification = buildAndGetRequestSpecification(pbsContainer.prometheusRootUri, authenticationScheme) } - BidResponse sendAuctionRequest(BidRequest bidRequest, Map headers = [:]) { + BidResponse sendAuctionRequest(BidRequest bidRequest, Integer expectedStatusCode = SC_OK) { + sendAuctionRequest(bidRequest, [:], expectedStatusCode) + } + + BidResponse sendAuctionRequest(BidRequest bidRequest, Map headers, int expectedStatusCode = SC_OK) { def response = postAuction(bidRequest, headers) - checkResponseStatusCode(response) + checkResponseStatusCode(response, expectedStatusCode) decode(response.body.asString(), BidResponse) } @@ -98,6 +102,7 @@ class PrebidServerService implements ObjectMapperWrapper { new RawAuctionResponse().tap { it.headers = getHeaders(response) + it.statusCode = response.statusCode() it.responseBody = response.body.asString() } } @@ -109,10 +114,14 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.body.asString(), AmpResponse) } - AmpResponse sendAmpRequest(AmpRequest ampRequest, Map headers = [:]) { + AmpResponse sendAmpRequest(AmpRequest ampRequest, int expectedStatusCode = SC_OK) { + sendAmpRequest(ampRequest, [:], expectedStatusCode) + } + + AmpResponse sendAmpRequest(AmpRequest ampRequest, Map headers, int expectedStatusCode = SC_OK) { def response = getAmp(ampRequest, headers) - checkResponseStatusCode(response) + checkResponseStatusCode(response, expectedStatusCode) decode(response.body.asString(), AmpResponse) } @@ -121,6 +130,7 @@ class PrebidServerService implements ObjectMapperWrapper { new RawAmpResponse().tap { it.headers = getHeaders(response) + it.statusCode = response.statusCode() it.responseBody = response.body.asString() } } @@ -372,9 +382,9 @@ class PrebidServerService implements ObjectMapperWrapper { .get(AMP_ENDPOINT) } - private void checkResponseStatusCode(Response response, int statusCode = 200) { + private void checkResponseStatusCode(Response response, int expectedStatusCode = SC_OK) { def responseStatusCode = response.statusCode - if (responseStatusCode != statusCode) { + if (responseStatusCode != expectedStatusCode) { def responseBody = response.body.asString() log.error(responseBody) throw new PrebidServerException(responseStatusCode, responseBody, getHeaders(response)) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index 02d627f141a..a58876862c4 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -1,6 +1,5 @@ package org.prebid.server.functional.testcontainers -import org.testcontainers.containers.InfluxDBContainer import org.testcontainers.containers.MySQLContainer import org.testcontainers.containers.PostgreSQLContainer @@ -33,6 +32,7 @@ LIMIT 1 "logging.sampling-rate" : "1.0", "auction.ad-server-currency" : DEFAULT_CURRENCY.value, "auction.stored-requests-timeout-ms" : "1000", + "auction.ortb-error-response" : "true", "metrics.prefix" : "prebid", "status-response" : "ok", "gdpr.default-value" : "0", @@ -101,6 +101,7 @@ LIMIT 1 "settings.database.idle-connection-timeout": "300" ].asImmutable() } + static Map getPostgreSqlConfig(PostgreSQLContainer postgres = Dependencies.postgresqlContainer) { ["settings.database.type" : "postgres", "settings.database.host" : postgres.getNetworkAliases().get(0), diff --git a/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy index 6bfb51536cc..d1a1e1bb88a 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy @@ -7,10 +7,12 @@ 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.BidRequest import org.prebid.server.functional.model.request.auction.Site -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class AccountSpec extends BaseSpec { @@ -30,12 +32,14 @@ class AccountSpec extends BaseSpec { } when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Account $accountId is inactive" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Account $accountId is inactive"] + } where: enforceValidAccount << [true, false] @@ -56,12 +60,14 @@ class AccountSpec extends BaseSpec { } when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: $accountId" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: $accountId"] + } where: defaultAccountConfig << [null, AccountConfig.defaultAccountConfig] @@ -79,12 +85,14 @@ class AccountSpec extends BaseSpec { } when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: " + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: "] + } where: defaultAccountConfig << [null, AccountConfig.defaultAccountConfig] @@ -137,13 +145,14 @@ class AccountSpec extends BaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - pbsService.sendAmpRequest(ampRequest) + def response = pbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) def resolvedAccount = requestAccount ?: storedRequestAccount - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: $resolvedAccount" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: $resolvedAccount"] + } where: defaultAccountConfig || requestAccount || storedRequestAccount @@ -175,12 +184,13 @@ class AccountSpec extends BaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - pbsService.sendAmpRequest(ampRequest) + def response = pbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: " + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: "] + } where: defaultAccountConfig << [null, AccountConfig.defaultAccountConfig] 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 9013978f76f..08242161eb8 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy @@ -4,11 +4,11 @@ import org.prebid.server.functional.model.bidder.AppNexus import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.bidder.Openx import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.BOGUS @@ -17,6 +17,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.GENER_X 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.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer import static org.prebid.server.functional.util.HttpUtil.CONTENT_ENCODING_HEADER @@ -105,12 +106,17 @@ class AliasSpec extends BaseSpec { bidRequest.ext.prebid.aliases = [(PBSUtils.randomString): GENERIC] when: "Sending auction request to PBS" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) 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.toLowerCase()}") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { + it.contains("Invalid request format: request.ext.prebid.aliasgvlids. " + + "vendorId ${validId} refers to unknown bidder alias: ${bidderName.toLowerCase()}") + } + } } def "PBS should return an error when GVL ID alias value is lower that one"() { @@ -121,13 +127,17 @@ class AliasSpec extends BaseSpec { bidRequest.ext.prebid.aliases = [(bidderName): GENERIC] when: "Sending auction request to PBS" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) 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.toLowerCase()}. Choose a different vendorId, or remove this entry.") - + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { + it.contains("Invalid request format: request.ext.prebid.aliasgvlids. " + + "Invalid vendorId ${invalidId} for alias: ${bidderName.toLowerCase()}. Choose a different vendorId, or remove this entry.") + } + } where: invalidId << [PBSUtils.randomNegativeNumber, 0] } @@ -140,13 +150,15 @@ class AliasSpec extends BaseSpec { } when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) 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.toLowerCase()} " + - "refers to unknown bidder: $BOGUS.value" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: request.ext.prebid.aliases.${randomString.toLowerCase()} " + + "refers to unknown bidder: $BOGUS.value"] + } } def "PBS aliased bidder config should be independently from parent"() { @@ -224,7 +236,7 @@ class AliasSpec extends BaseSpec { assert !bidResponse.ext.debug.httpcalls and: "Bid response should contain warning" - assert bidResponse.ext?.warnings[PREBID]?.code == [999, 999] + assert bidResponse.ext?.warnings[PREBID]?.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.${APPNEXUS.value} was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.${APPNEXUS.value} failed validation.\n" + 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 1e2c67fad6f..2f40ee5cbb7 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -13,14 +13,15 @@ import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.PrebidStoredRequest import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.request.auction.Targeting +import org.prebid.server.functional.model.response.BidderErrorCode 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.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils import spock.lang.Shared +import static org.apache.http.HttpStatus.SC_BAD_REQUEST 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 @@ -33,6 +34,8 @@ import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL 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.response.auction.BidRejectionReason.RESPONSE_REJECTED_GENERAL +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class AlternateBidderCodeSpec extends BaseSpec { @@ -626,13 +629,15 @@ class AlternateBidderCodeSpec extends BaseSpec { flushMetrics(pbsServiceWithAmxBidder) when: "PBS processes auction request" - pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxBidder.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == "Invalid request format: " + - "request.ext.prebid.alternatebiddercodes.bidders.unknown is not a known bidder or alias" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: " + + "request.ext.prebid.alternatebiddercodes.bidders.unknown is not a known bidder or alias"] + } where: diff --git a/src/test/groovy/org/prebid/server/functional/tests/AmpFpdSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AmpFpdSpec.groovy index e376f611e84..16a56b1105f 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AmpFpdSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AmpFpdSpec.groovy @@ -16,15 +16,16 @@ import org.prebid.server.functional.model.request.auction.ImpExtContextDataAdSer import org.prebid.server.functional.model.request.auction.Publisher import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.request.auction.User -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST 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.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID class AmpFpdSpec extends BaseSpec { @@ -125,13 +126,14 @@ class AmpFpdSpec extends BaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - defaultPbsService.sendAmpRequest(ampRequest) + def response = defaultPbsService.sendAmpRequest(ampRequest, SC_BAD_REQUEST) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody.startsWith("Invalid request format: " + - "Error reading targeting json Unrecognized token '$invalidTargeting': was expecting") + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.startsWith("Invalid request format: " + + "Error reading targeting json Unrecognized token '$invalidTargeting': was expecting") } + } } def "PBS shouldn't populate FPD field via targeting when targeting field is absent"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/AmpSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AmpSpec.groovy index 47e08555828..258a4889152 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AmpSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AmpSpec.groovy @@ -10,11 +10,13 @@ import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.request.auction.StoredAuctionResponse import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.SeatBid -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST +import static org.prebid.server.functional.model.response.BidderErrorCode.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.util.SystemProperties.PBS_VERSION class AmpSpec extends BaseSpec { @@ -51,13 +53,13 @@ class AmpSpec extends BaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - defaultPbsService.sendAmpRequest(ampRequest) + def response = defaultPbsService.sendAmpRequest(ampRequest, SC_BAD_REQUEST) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: request.${channel.value.toLowerCase()} must not exist in AMP stored requests." - + verifyAll(response.ext.errors[PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: request.${channel.value.toLowerCase()} must not exist in AMP stored requests."] + } where: channel << [DistributionChannel.APP, DistributionChannel.DOOH] } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy index 1506e2e0a4d..35dd8f617a3 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy @@ -17,24 +17,27 @@ import org.prebid.server.functional.model.request.auction.Sdk import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt import org.prebid.server.functional.model.request.auction.UserExtPrebid +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidExt import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.Meta import org.prebid.server.functional.model.response.auction.Prebid import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.HttpUtil import org.prebid.server.functional.util.PBSUtils import spock.lang.Shared +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.AccountStatus.INACTIVE import static org.prebid.server.functional.model.bidder.BidderName.ALIAS 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.GENERIC_CAMEL_CASE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.REDIRECT import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer import static org.prebid.server.functional.util.HttpUtil.COOKIE_DEPRECATION_HEADER @@ -83,12 +86,14 @@ class AuctionSpec extends BaseSpec { accountDao.save(account) when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 401 - assert exception.responseBody == "Account ${accountId} is inactive" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Account ${accountId} is inactive"] + } and: "account..requests.rejected.invalid-account metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() @@ -108,13 +113,14 @@ class AuctionSpec extends BaseSpec { def initialMetricCount = getCurrentMetricValue(defaultPbsService, fullMetricName) when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Request fails with an stored request id is not found error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == - "Invalid request format: Stored request processing failed: Id is not found in storedRequest" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Account ${accountId} is inactive"] + } and: "Metric count is updated" assert getCurrentMetricValue(defaultPbsService, fullMetricName) == initialMetricCount + 1 @@ -591,7 +597,7 @@ class AuctionSpec extends BaseSpec { then: "PBS should include warning in responce" def auctionWarnings = response.ext?.warnings?.get(PREBID) assert auctionWarnings.size() == 1 - assert auctionWarnings[0].code == 999 + assert auctionWarnings[0].code == BidderErrorCode.GENERIC assert auctionWarnings[0].message == 'Sec-Cookie-Deprecation header has invalid value' and: "BidderRequest shouldn't have device.ext.cdep" @@ -747,7 +753,7 @@ class AuctionSpec extends BaseSpec { assert !response?.ext?.seatnonbid and: "PBS should emit an warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["Only first $IMP_LIMIT impressions were kept due to the limit, " + "all the subsequent impressions have been dropped for the auction" as String] 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 7da1c89fffb..430d24b95a2 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy @@ -17,16 +17,16 @@ 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.BidderErrorCode 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 import org.prebid.server.functional.testcontainers.PbsConfig import org.prebid.server.functional.testcontainers.scaffolding.CurrencyConversion import org.prebid.server.functional.util.CurrencyUtil import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_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 @@ -51,6 +51,7 @@ import static org.prebid.server.functional.model.request.auction.DistributionCha import static org.prebid.server.functional.model.request.auction.VideoPlacementSubtypes.IN_STREAM as IN_PLACEMENT_STREAM import static org.prebid.server.functional.model.request.auction.VideoPlcmtSubtype.IN_STREAM as IN_PLCMT_STREAM import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer import static org.prebid.server.functional.util.PBSUtils.getRandomDecimal @@ -187,13 +188,14 @@ class BidAdjustmentSpec extends BaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should fail the request" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody.contains("Invalid request format: request.ext.prebid.bidadjustmentfactors.$bidderName.value must be a positive number") - + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.contains("Invalid request format: request.ext.prebid.bidadjustmentfactors.$bidderName.value must be a positive number") } + } where: bidAdjustmentFactor << [MIN_ADJUST_VALUE, PBSUtils.randomNegativeNumber] } @@ -886,7 +888,7 @@ class BidAdjustmentSpec extends BaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=${adjustmentType}, " + "value=${ruleValue}, currency=${currency}] in ${mediaType.value}.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" @@ -1065,7 +1067,7 @@ class BidAdjustmentSpec extends BaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=${adjustmentType}, " + "value=${adjustmentPrice}, currency=null] in banner.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" @@ -1165,7 +1167,7 @@ class BidAdjustmentSpec extends BaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=UNKNOWN, " + "value=$adjustmentPrice, currency=$currency] in banner.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidValidationSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidValidationSpec.groovy index 9dd17c31e0a..d846e9efeaa 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidValidationSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidValidationSpec.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.tests +import org.apache.http.HttpStatus import org.prebid.server.functional.model.request.auction.App import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.DistributionChannel @@ -8,19 +9,22 @@ import org.prebid.server.functional.model.request.auction.Eid import org.prebid.server.functional.model.request.auction.MultiBid import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.request.auction.User +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature import java.time.Instant +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.request.auction.DebugCondition.DISABLED import static org.prebid.server.functional.model.request.auction.DebugCondition.ENABLED import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.util.HttpUtil.REFERER_HEADER class BidValidationSpec extends BaseSpec { @@ -54,12 +58,14 @@ class BidValidationSpec extends BaseSpec { flushMetrics(strictPrebidService) when: "PBS processes auction request" - strictPrebidService.sendAuctionRequest(bidRequest) + def response = strictPrebidService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS throws an exception" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody.contains("no more than one of request.site or request.app or request.dooh can be defined") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.contains("no more than one of request.site or request.app or request.dooh can be defined") } + } and: "Bid validation metric value is incremented" def metrics = strictPrebidService.sendCollectedMetricsRequest() @@ -99,8 +105,8 @@ class BidValidationSpec extends BaseSpec { then: "Response should contain warning" def warningChannelsValues = requestDistributionChannels.collect { "${it.value.toLowerCase()}" }.join(" and ") - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == ["BidRequest contains $warningChannelsValues. Only the first one is applicable, the others are ignored" as String] and: "Bid validation metric value is incremented" @@ -138,12 +144,15 @@ class BidValidationSpec extends BaseSpec { bidDoohRequest.ext.prebid.debug = ENABLED when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidDoohRequest) + def response = defaultPbsService.sendAuctionRequest(bidDoohRequest, SC_BAD_REQUEST) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.responseBody.contains("request.dooh should include at least one of request.dooh.id " + - "or request.dooh.venuetype.") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.contains("request.dooh should include at least one of request.dooh.id " + + "or request.dooh.venuetype.") } + } } def "PBS should validate site when it is present"() { @@ -153,11 +162,14 @@ class BidValidationSpec extends BaseSpec { bidRequest.ext.prebid.debug = ENABLED when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, HttpStatus.SC_BAD_REQUEST) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.responseBody.contains("request.site should include at least one of request.site.id or request.site.page") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.contains("request.site should include at least one of request.site.id or request.site.page") } + } } def "PBS should treat bids with 0 price as valid when deal id is present"() { @@ -212,8 +224,8 @@ class BidValidationSpec extends BaseSpec { assert !response.ext.seatnonbid and: "PBS should emit an error" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == ["Dropped bid '$bidId'. Does not contain a positive (or zero if there is a deal) 'price'" as String] where: @@ -298,8 +310,8 @@ class BidValidationSpec extends BaseSpec { assert response.seatbid?.first()?.bid*.id == [validBidId] and: "PBS should emit an error" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == ["Dropped bid '$invalidBid.id'. Does not contain a positive (or zero if there is a deal) 'price'" as String] where: diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy index b47a2e47ddf..96a641269b9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy @@ -15,13 +15,14 @@ import org.prebid.server.functional.model.request.auction.Format import org.prebid.server.functional.model.request.auction.Native import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.request.auction.Video +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature import spock.lang.Shared +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.config.BidValidationEnforcement.ENFORCE import static org.prebid.server.functional.model.config.BidValidationEnforcement.SKIP @@ -29,6 +30,8 @@ import static org.prebid.server.functional.model.config.BidValidationEnforcement import static org.prebid.server.functional.model.request.auction.SecurityLevel.NON_SECURE import static org.prebid.server.functional.model.request.auction.SecurityLevel.SECURE import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class BidderFormatSpec extends BaseSpec { @@ -50,7 +53,7 @@ class BidderFormatSpec extends BaseSpec { assert bidderRequest?.imp[0]?.banner?.format[0].height == bannerFormatHeight where: - bannerFormatWidth | bannerFormatHeight + bannerFormatWidth | bannerFormatHeight 1 | 1 PBSUtils.randomNumber | PBSUtils.randomNumber } @@ -62,16 +65,18 @@ class BidderFormatSpec extends BaseSpec { } when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to banner.format{w.h} validation" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == "Invalid request format: " + - "request.imp[0].banner.format[0] must define a valid \"h\" and \"w\" properties" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: " + + "request.imp[0].banner.format[0] must define a valid \"h\" and \"w\" properties"] + } where: - bannerFormatWidth | bannerFormatHeight + bannerFormatWidth | bannerFormatHeight 0 | PBSUtils.randomNumber PBSUtils.randomNumber | 0 null | PBSUtils.randomNumber @@ -87,17 +92,19 @@ class BidderFormatSpec extends BaseSpec { } when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to banner.format{w.h} validation" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == "Invalid request format: request.imp[0].banner.format[0] " + - "should define *either* {w, h} (for static size requirements) " + - "*or* {wmin, wratio, hratio} (for flexible sizes) to be non-zero positive" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: request.imp[0].banner.format[0] " + + "should define *either* {w, h} (for static size requirements) " + + "*or* {wmin, wratio, hratio} (for flexible sizes) to be non-zero positive"] + } where: - bannerFormatWidth | bannerFormatHeight + bannerFormatWidth | bannerFormatHeight 0 | 0 0 | null 0 | PBSUtils.randomNegativeNumber @@ -121,7 +128,7 @@ class BidderFormatSpec extends BaseSpec { assert bidderRequest?.imp[0]?.banner?.height == bannerFormatHeight where: - bannerFormatWidth | bannerFormatHeight + bannerFormatWidth | bannerFormatHeight 1 | 1 PBSUtils.randomNumber | PBSUtils.randomNumber } @@ -133,16 +140,18 @@ class BidderFormatSpec extends BaseSpec { } when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) - then: "PBs should throw error due to banner{w.h} validation" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == "Invalid request format: " + - "request.imp[0].banner has no sizes. Define \"w\" and \"h\", or include \"format\" elements" + then: "PBs should throw error due to banner.format{w.h} validation" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: " + + "request.imp[0].banner has no sizes. Define \"w\" and \"h\", or include \"format\" elements"] + } where: - bannerFormatWidth | bannerFormatHeight + bannerFormatWidth | bannerFormatHeight 0 | 0 0 | PBSUtils.randomNumber PBSUtils.randomNumber | 0 @@ -212,7 +221,7 @@ class BidderFormatSpec extends BaseSpec { assert !bidder.getBidderRequests(bidRequest.id) where: - accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight + accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight null | WARN.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER + 1 null | WARN.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER null | WARN.value | RANDOM_NUMBER | RANDOM_NUMBER + 1 @@ -270,7 +279,7 @@ class BidderFormatSpec extends BaseSpec { assert !bidder.getBidderRequests(bidRequest.id) where: - accountCretiveMaxSizeSnakeCase | accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight + accountCretiveMaxSizeSnakeCase | accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight null | null | SKIP.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER + 1 null | null | SKIP.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER null | null | SKIP.value | RANDOM_NUMBER | RANDOM_NUMBER + 1 @@ -341,7 +350,7 @@ class BidderFormatSpec extends BaseSpec { assert !bidder.getBidderRequests(bidRequest.id) where: - accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight + accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight null | ENFORCE.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER + 1 null | ENFORCE.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER null | ENFORCE.value | RANDOM_NUMBER | RANDOM_NUMBER + 1 @@ -451,7 +460,7 @@ class BidderFormatSpec extends BaseSpec { assert !bidder.getBidderRequests(bidRequest.id) where: - accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight + accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight null | ENFORCE.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER + 1 null | ENFORCE.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER null | ENFORCE.value | RANDOM_NUMBER | RANDOM_NUMBER + 1 @@ -528,7 +537,7 @@ class BidderFormatSpec extends BaseSpec { assert !bidder.getBidderRequests(bidRequest.id) where: - accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight + accountCretiveMaxSize | configCreativeMaxSize | responseWidth | responseHeight ENFORCE | WARN.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER + 1 ENFORCE | WARN.value | RANDOM_NUMBER + 1 | RANDOM_NUMBER ENFORCE | WARN.value | RANDOM_NUMBER | RANDOM_NUMBER + 1 diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy index f2fb2803f1f..484fc0e4984 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy @@ -19,6 +19,7 @@ import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt import org.prebid.server.functional.model.request.auction.UserExtPrebid import org.prebid.server.functional.model.request.cookiesync.CookieSyncRequest +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType @@ -28,6 +29,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT class BidderInsensitiveCaseSpec extends BaseSpec { @@ -321,7 +323,7 @@ class BidderInsensitiveCaseSpec extends BaseSpec { assert response.seatbid.isEmpty() and: "Response should contain error" - assert response.ext?.warnings[ErrorType.GENERIC_CAMEL_CASE]*.code == [2] + assert response.ext?.warnings[ErrorType.GENERIC_CAMEL_CASE]*.code == [BAD_INPUT] assert response.ext?.warnings[ErrorType.GENERIC_CAMEL_CASE]*.message == ["Bidder does not support any media types."] } 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 220585f008f..c01cdbf4a71 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -9,11 +9,11 @@ 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.AnyUnsupportedBidder 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 import org.prebid.server.functional.model.request.auction.Device -import org.prebid.server.functional.model.request.auction.AnyUnsupportedBidder import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.ImpExt @@ -28,6 +28,7 @@ import org.prebid.server.functional.model.request.auction.Source 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.BidderErrorCode 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 @@ -335,7 +336,7 @@ class BidderParamsSpec extends BaseSpec { def response = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain error" - assert response.ext?.errors[GENERIC]*.code == [999] + assert response.ext?.errors[GENERIC]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[GENERIC]*.message == ["host name must not be empty"] cleanup: "Stop and remove pbs container" @@ -359,7 +360,7 @@ class BidderParamsSpec extends BaseSpec { assert bidder.getRequestCount(bidRequest.id) == 1 and: "Bidder with invalid params should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + @@ -387,7 +388,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + @@ -417,7 +418,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + @@ -444,7 +445,7 @@ class BidderParamsSpec extends BaseSpec { assert response.seatbid.isEmpty() and: "Response should contain error" - assert response.ext?.warnings[GENERIC]*.code == [2] + assert response.ext?.warnings[GENERIC]*.code == [BidderErrorCode.BAD_INPUT] assert response.ext?.warnings[GENERIC]*.message == ["Bidder does not support any media types."] cleanup: "Stop and remove pbs container" @@ -573,7 +574,7 @@ class BidderParamsSpec extends BaseSpec { assert bidderRequest.imp[0].nativeObj and: "Response should contain error" - assert response.ext?.warnings[GENERIC]*.code == [2] + assert response.ext?.warnings[GENERIC]*.code == [BidderErrorCode.BAD_INPUT] assert response.ext?.warnings[GENERIC]*.message == ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from the " + "request for this bidder." as String] @@ -670,7 +671,7 @@ class BidderParamsSpec extends BaseSpec { assert bidder.getRequestCount(bidRequest.id) == 0 and: "Response should contain errors" - assert response.ext?.warnings[GENERIC]*.code == [2, 2] + assert response.ext?.warnings[GENERIC]*.code == [BidderErrorCode.BAD_INPUT, BidderErrorCode.BAD_INPUT] assert response.ext?.warnings[GENERIC]*.message == ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from " + "the request for this bidder.", @@ -849,7 +850,7 @@ class BidderParamsSpec extends BaseSpec { assert bidderRequest.imp[0].ext.anyUnsupportedBidder == unsupportedBidder and: "PBS should emit an warning" - assert response?.ext?.warnings[PREBID]*.code == [999] + assert response?.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response?.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.anyUnsupportedBidder was dropped with a reason: " + "request.imp[0].ext.prebid.bidder contains unknown bidder: anyUnsupportedBidder"] @@ -870,7 +871,7 @@ class BidderParamsSpec extends BaseSpec { assert !response.ext?.errors and: "PBS should emit an warning" - assert response?.ext?.warnings[PREBID]*.code == [999] + assert response?.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response?.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.adUnitCode was dropped with a reason: " + "request.imp[0].ext.prebid.bidder contains unknown bidder: adUnitCode"] @@ -1140,7 +1141,7 @@ class BidderParamsSpec extends BaseSpec { assert response.ext.seatnonbid.size() == 1 and: "PBS should emit an warnings" - assert response.ext?.warnings[GENERIC]*.code == [999] + assert response.ext?.warnings[GENERIC]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[GENERIC]*.message == ["No match between the configured currencies and bidRequest.cur"] @@ -1234,7 +1235,7 @@ class BidderParamsSpec extends BaseSpec { assert !response.ext?.errors and: "PBS should emit an warnings" - assert response.ext?.warnings[ALIAS]*.code == [999] + assert response.ext?.warnings[ALIAS]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ALIAS]*.message == ["No match between the configured currencies and bidRequest.cur"] @@ -1326,7 +1327,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + @@ -1357,7 +1358,7 @@ class BidderParamsSpec extends BaseSpec { def response = defaultPbsService.sendAuctionRequest(bidRequest) then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index ce17a673424..d873a6e6af0 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -8,13 +8,14 @@ import org.prebid.server.functional.model.request.auction.Asset 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.Targeting +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.util.PBSUtils -import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.response.auction.MediaType.BANNER import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer @@ -499,7 +500,7 @@ class CacheSpec extends BaseSpec { def bidResponse = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain error" - assert bidResponse.ext?.errors[CACHE]*.code == [999] + assert bidResponse.ext?.errors[CACHE]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.errors[CACHE]*.message[0] == ("Failed to resolve '${CACHE_HOST.tokenize(":")[0]}' [A(1)]") and: "Bid response targeting should contain value" @@ -542,7 +543,7 @@ class CacheSpec extends BaseSpec { assert cacheCall.uri == "${HTTP_SCHEME}://${networkServiceContainer.hostAndPort + INTERNAL_CACHE_PATH}" then: "Response should contain error" - assert bidResponse.ext?.errors[CACHE]*.code == [999] + assert bidResponse.ext?.errors[CACHE]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.errors[CACHE]*.message[0] == ("Failed to resolve '${CACHE_HOST.tokenize(":")[0]}' [A(1)]") cleanup: "Stop and remove pbs container" diff --git a/src/test/groovy/org/prebid/server/functional/tests/DebugSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/DebugSpec.groovy index ea169ad00ee..cb4159c74c5 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/DebugSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/DebugSpec.groovy @@ -11,12 +11,12 @@ import org.prebid.server.functional.model.request.amp.AmpRequest import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.request.auction.StoredBidResponse +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.model.response.auction.ErrorType -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.BASIC import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.DETAILED @@ -24,6 +24,8 @@ import static org.prebid.server.functional.model.config.AccountMetricsVerbosityL import static org.prebid.server.functional.model.request.auction.DebugCondition.DISABLED import static org.prebid.server.functional.model.request.auction.DebugCondition.ENABLED import static org.prebid.server.functional.model.response.auction.BidderCallType.STORED_BID_RESPONSE +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class DebugSpec extends BaseSpec { @@ -106,8 +108,8 @@ class DebugSpec extends BaseSpec { assert !response.ext?.debug?.httpcalls and: "Response should contain specific code and text in ext.warnings.general" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] // [10003] - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == + assert response.ext?.warnings[PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] // [10003] + assert response.ext?.warnings[PREBID]?.collect { it.message } == ["Debug turned off for bidder: $GENERIC.value" as String] } @@ -149,9 +151,9 @@ class DebugSpec extends BaseSpec { and: "Response should contain specific code and text in ext.warnings.general" //TODO change to 10002 after updating debug warnings - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] //TODO possibly change message after clarifications - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == + assert response.ext?.warnings[PREBID]?.collect { it.message } == ["Debug turned off for account"] where: @@ -179,8 +181,8 @@ class DebugSpec extends BaseSpec { and: "Response should contain specific code and text in ext.warnings.general" //TODO change to 10003 after updating debug warnings - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == + assert response.ext?.warnings[PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]?.collect { it.message } == ["Debug turned off for bidder: $GENERIC.value" as String] where: @@ -209,8 +211,8 @@ class DebugSpec extends BaseSpec { and: "Response should contain specific code and text in ext.warnings.general" //TODO change to 10002 after updating debug warnings - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["Debug turned off for account"] + assert response.ext?.warnings[PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]?.collect { it.message } == ["Debug turned off for account"] } def "PBS should use default values = true for bidder-level setting debug.allow and account-level setting debug-allowed when they are not specified"() { @@ -281,8 +283,8 @@ class DebugSpec extends BaseSpec { and: "Response should contain specific code and text in ext.warnings.general" //TODO change to 10002 after updating debug warnings - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["Debug turned off for account"] + assert response.ext?.warnings[PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]?.collect { it.message } == ["Debug turned off for account"] where: headerValue << [StringUtils.swapCase(overrideToken), PBSUtils.randomString] @@ -521,11 +523,14 @@ class DebugSpec extends BaseSpec { flushMetrics(defaultPbsService) when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.responseBody.contains("request.site should include at least one of request.site.id or request.site.page") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.contains("request.site should include at least one of request.site.id or request.site.page") } + } and: "Debug metrics shouldn't be populated" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() diff --git a/src/test/groovy/org/prebid/server/functional/tests/EidsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/EidsSpec.groovy index 6bc172f3fa4..662733e3936 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/EidsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/EidsSpec.groovy @@ -10,10 +10,10 @@ import org.prebid.server.functional.model.request.auction.Uid import org.prebid.server.functional.model.request.auction.UidExt import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE @@ -24,6 +24,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD import static org.prebid.server.functional.model.request.auction.DebugCondition.DISABLED import static org.prebid.server.functional.model.request.auction.DebugCondition.ENABLED import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class EidsSpec extends BaseSpec { @@ -141,7 +142,7 @@ class EidsSpec extends BaseSpec { assert !bidderRequest.user.eids and: "Bid response should contain warning" - assert bidResponse.ext.warnings[PREBID]?.code == [999] + assert bidResponse.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert bidResponse.ext.warnings[PREBID]?.message == ["request.ext.prebid.data.eidPermissions[].bidders[] unrecognized biddercode: '$UNKNOWN'"] @@ -231,12 +232,15 @@ class EidsSpec extends BaseSpec { } when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should throw error" - def exception = thrown(PrebidServerException) - assert exception.responseBody == "Invalid request format: request.ext.prebid.data.eidpermissions[].bidders[] " + - "required values but was empty or null" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: request.ext.prebid.data.eidpermissions[].bidders[] " + + "required values but was empty or null"] + } where: eidsBidder << [[WILDCARD], [], null] @@ -288,7 +292,7 @@ class EidsSpec extends BaseSpec { assert bidderRequest.user.eids.uids.id.flatten() == [validUidId] and: "Bid response should contain warning" - assert bidResponse.ext.warnings[PREBID]?.code == [999] + assert bidResponse.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert bidResponse.ext.warnings[PREBID]?.message == ["removed EID ${sourceId} due to empty ID" as String] @@ -313,7 +317,7 @@ class EidsSpec extends BaseSpec { assert !bidderRequest.user.eids and: "Bid response should contain warnings" - assert bidResponse.ext.warnings[PREBID]?.code == [999, 999, 999] + assert bidResponse.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC, BidderErrorCode.GENERIC, BidderErrorCode.GENERIC] assert bidResponse.ext.warnings[PREBID]?.message == ["removed EID ${sourceId} due to empty ID" as String, "removed EID ${sourceId} due to empty ID" as String, @@ -584,13 +588,15 @@ class EidsSpec extends BaseSpec { } when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should throw error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: " + - "Missing required parameter(s) in request.ext.prebid.data.eidPermissions[]. " + - "Either one or a combination of inserter, source, matcher, or mm should be defined." + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ["Invalid request format: " + + "Missing required parameter(s) in request.ext.prebid.data.eidPermissions[]. " + + "Either one or a combination of inserter, source, matcher, or mm should be defined."] + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/ImpRequestSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/ImpRequestSpec.groovy index 7a2f5923d56..eb705c57cc3 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/ImpRequestSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/ImpRequestSpec.groovy @@ -7,6 +7,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.Pmp import org.prebid.server.functional.model.request.auction.PrebidStoredRequest +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils @@ -15,11 +16,11 @@ import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_CAMEL_C 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.GENER_X import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.RUBICON 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.bidder.BidderName.GENER_X import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer @@ -182,7 +183,7 @@ class ImpRequestSpec extends BaseSpec { def response = defaultPbsServiceWithAlias.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == ["WARNING: request.imp[0].ext.prebid.imp.${bidderName} was dropped with the reason: invalid bidder"] @@ -278,7 +279,7 @@ class ImpRequestSpec extends BaseSpec { def response = defaultPbsServiceWithAlias.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == ["imp.ext.prebid.imp.generic can not be merged into original imp [id=${bidRequest.imp.first.id}], " + "reason: imp[id=] missing required field: \"id\""] diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index 4e0253c1f95..7ee86efe49b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -4,10 +4,12 @@ import org.prebid.server.functional.model.AccountStatus import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer class InfluxDBSpec extends BaseSpec { @@ -43,12 +45,14 @@ class InfluxDBSpec extends BaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest) + def response = pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Account $bidRequest.accountId is inactive" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Account $bidRequest.accountId is inactive"] + } and: "PBS wait until get metric" assert pbsServiceWithEnforceValidAccount.isContainMetricByValue(ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId)) diff --git a/src/test/groovy/org/prebid/server/functional/tests/OrtbErrorResponseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/OrtbErrorResponseSpec.groovy new file mode 100644 index 00000000000..c0b4aeab92c --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/OrtbErrorResponseSpec.groovy @@ -0,0 +1,216 @@ +package org.prebid.server.functional.tests + +import org.prebid.server.functional.model.db.Account +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.BidRequest +import org.prebid.server.functional.service.PrebidServerService + +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED +import static org.prebid.server.functional.model.AccountStatus.INACTIVE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR + +class OrtbErrorResponseSpec extends BaseSpec { + + private static final Closure ACCOUNT_INVALID_MESSAGE = { accountId -> "Account ${accountId} is inactive" } + private static final PrebidServerService disabledOrtbErrorResponseConfigPbsService = pbsServiceFactory.getService(["auction.ortb-error-response": "false"]) + + @Override + def cleanupSpec() { + pbsServiceFactory.removeContainer(["auction.ortb-error-response": "false"]) + } + + def "PBS auction should provide proper ORTB error response when ortb-error-response host config is enabled"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest + + and: "Invalid account in DB" + def account = new Account(uuid: bidRequest.accountId, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes auction request" + def response = disabledOrtbErrorResponseConfigPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) + + then: "Response should be with error" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == [ACCOUNT_INVALID_MESSAGE(bidRequest.accountId)] + } + } + + def "PBS auction should provide raw error response when ortb-error-response host config is disabled"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest + + and: "Invalid account in DB" + def account = new Account(uuid: bidRequest.accountId, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes auction request" + def response = disabledOrtbErrorResponseConfigPbsService.sendAuctionRequestRaw(bidRequest) + + then: "Response should be with error" + assert response.statusCode == SC_UNAUTHORIZED + assert response.responseBody == ACCOUNT_INVALID_MESSAGE(bidRequest.accountId) + } + + def "PBS auction should provide raw error response and ignore host config when ortb-errors host config is disabled"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.ortbErrors = false + } + + and: "Invalid account in DB" + def account = new Account(uuid: bidRequest.accountId, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequestRaw(bidRequest) + + then: "Response should be with error" + assert response.statusCode == SC_UNAUTHORIZED + assert response.responseBody == ACCOUNT_INVALID_MESSAGE(bidRequest.accountId) + + where: + pbsService << [disabledOrtbErrorResponseConfigPbsService, defaultPbsService] + } + + def "PBS auction should provide proper ORTB error response and ignore host config when ortb-errors host config is enabled"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.ortbErrors = true + } + + and: "Invalid account in DB" + def account = new Account(uuid: bidRequest.accountId, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) + + then: "Response should be with error" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == [ACCOUNT_INVALID_MESSAGE(bidRequest.accountId)] + } + + where: + pbsService << [disabledOrtbErrorResponseConfigPbsService, defaultPbsService] + } + + def "PBS amp should provide proper ORTB error response when ortb-error-response host config is enabled"() { + given: "Default AmpRequest" + def ampRequest = AmpRequest.defaultAmpRequest + + and: "Default basic BidRequest" + def ampStoredRequest = BidRequest.defaultBidRequest.tap { + setAccountId(ampRequest.account) + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) + storedRequestDao.save(storedRequest) + + and: "Invalid account in DB" + def account = new Account(uuid: ampRequest.account, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes amp request" + def response = disabledOrtbErrorResponseConfigPbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) + + then: "Response should be with error" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == [ACCOUNT_INVALID_MESSAGE(ampRequest.account)] + } + } + + def "PBS amp should provide raw error response when ortb-error-response host config is disabled"() { + given: "Default AmpRequest" + def ampRequest = AmpRequest.defaultAmpRequest + + and: "Default basic BidRequest" + def ampStoredRequest = BidRequest.defaultBidRequest.tap { + setAccountId(ampRequest.account) + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) + storedRequestDao.save(storedRequest) + + and: "Invalid account in DB" + def account = new Account(uuid: ampRequest.account, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes amp request" + def response = disabledOrtbErrorResponseConfigPbsService.sendAmpRequestRaw(ampRequest) + + then: "Response should be with error" + assert response.statusCode == SC_UNAUTHORIZED + assert response.responseBody == ACCOUNT_INVALID_MESSAGE(ampRequest.account) + } + + def "PBS amp should provide raw error response and ignore host config when ortb-errors host config is disabled"() { + given: "Default AmpRequest" + def ampRequest = AmpRequest.defaultAmpRequest + + and: "Default basic BidRequest" + def ampStoredRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.ortbErrors = false + setAccountId(ampRequest.account) + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) + storedRequestDao.save(storedRequest) + + and: "Invalid account in DB" + def account = new Account(uuid: ampRequest.account, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes amp request" + def response = pbsService.sendAmpRequestRaw(ampRequest) + + then: "Response should be with error" + assert response.statusCode == SC_UNAUTHORIZED + assert response.responseBody == ACCOUNT_INVALID_MESSAGE(ampRequest.account) + + where: + pbsService << [disabledOrtbErrorResponseConfigPbsService, defaultPbsService] + } + + def "PBS amp should provide proper ORTB error response and ignore host config when ortb-errors host config is enabled"() { + given: "Default AmpRequest" + def ampRequest = AmpRequest.defaultAmpRequest + + and: "Default basic BidRequest" + def ampStoredRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.ortbErrors = true + setAccountId(ampRequest.account) + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) + storedRequestDao.save(storedRequest) + + and: "Invalid account in DB" + def account = new Account(uuid: ampRequest.account, status: INACTIVE) + accountDao.save(account) + + when: "PBS processes amp request" + def response = pbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) + + then: "Response should be with error" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == [ACCOUNT_INVALID_MESSAGE(ampRequest.account)] + } + + where: + pbsService << [disabledOrtbErrorResponseConfigPbsService, defaultPbsService] + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy index c6d600d518c..e63f591965e 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy @@ -17,31 +17,33 @@ import org.prebid.server.functional.model.request.auction.Format import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.ImpExt import org.prebid.server.functional.model.request.auction.ImpExtPrebid +import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.request.auction.StoredAuctionResponse import org.prebid.server.functional.model.request.auction.StoredBidResponse -import org.prebid.server.functional.model.request.profile.Profile import org.prebid.server.functional.model.request.profile.ImpProfile +import org.prebid.server.functional.model.request.profile.Profile import org.prebid.server.functional.model.request.profile.ProfileMergePrecedence -import org.prebid.server.functional.model.request.profile.RequestProfile import org.prebid.server.functional.model.request.profile.ProfileType -import org.prebid.server.functional.model.request.auction.Site +import org.prebid.server.functional.model.request.profile.RequestProfile +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.model.response.auction.SeatBid import org.prebid.server.functional.repository.dao.ProfileImpDao import org.prebid.server.functional.repository.dao.ProfileRequestDao -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.PBSUtils import org.testcontainers.images.builder.Transferable import spock.lang.PendingFeature +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.request.profile.ProfileMergePrecedence.PROFILE import static org.prebid.server.functional.model.request.profile.ProfileMergePrecedence.REQUEST +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class ProfileSpec extends BaseSpec { @@ -637,8 +639,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [LIMIT_ERROR_MESSAGE] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [LIMIT_ERROR_MESSAGE] and: "Response should contain error" assert !response.ext?.errors @@ -808,7 +810,7 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.message.contains(LIMIT_ERROR_MESSAGE) + assert response.ext?.warnings[PREBID]*.message.contains(LIMIT_ERROR_MESSAGE) and: "Response should contain error" assert !response.ext?.errors @@ -928,12 +930,14 @@ class ProfileSpec extends BaseSpec { } when: "PBS processes auction request" - prebidServerService.sendAuctionRequest(bidRequest) + def response = prebidServerService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to invalid profile" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId) + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == [INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId)] + } cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(PROFILES_CONFIG + ['auction.profiles.fail-on-unknown': 'true']) @@ -954,12 +958,14 @@ class ProfileSpec extends BaseSpec { } when: "PBS processes auction request" - prebidServerService.sendAuctionRequest(bidRequest) + def response = prebidServerService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to invalid profile" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId) + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == [INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId)] + } cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(PROFILES_CONFIG + ['auction.profiles.fail-on-unknown': null]) @@ -986,12 +992,14 @@ class ProfileSpec extends BaseSpec { flushMetrics(pbsWithStoredProfiles) when: "PBS processes auction request" - pbsWithStoredProfiles.sendAuctionRequest(bidRequest) + def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to invalid profile" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId) + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == [INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId)] + } and: "Missing metric should increments" def metrics = pbsWithStoredProfiles.sendCollectedMetricsRequest() @@ -1102,12 +1110,14 @@ class ProfileSpec extends BaseSpec { profileImpDao.save(StoredProfileImp.getProfile(impProfile)) when: "PBS processes auction request" - pbsWithStoredProfiles.sendAuctionRequest(bidRequest) + def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBs should throw error due to invalid request" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == 'Invalid request format: request.imp[0].banner.format[0] must define a valid "h" and "w" properties' + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ['Invalid request format: request.imp[0].banner.format[0] must define a valid "h" and "w" properties'] + } } def "PBS shouldn't emit error or warnings when bidRequest contains multiple imps with same profile"() { @@ -1190,8 +1200,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [LIMIT_ERROR_MESSAGE] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [LIMIT_ERROR_MESSAGE] and: "Response should contain error" assert !response.ext?.errors @@ -1234,8 +1244,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_PROFILE_MESSAGE.formatted(requestProfile.id)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_PROFILE_MESSAGE.formatted(requestProfile.id)] and: "Response should contain error" assert !response.ext?.errors @@ -1288,8 +1298,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_PROFILE_MESSAGE.formatted(requestProfile.id)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_PROFILE_MESSAGE.formatted(requestProfile.id)] and: "Response should contain error" assert !response.ext?.errors @@ -1337,8 +1347,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId)] and: "Response should contain error" assert !response.ext?.errors @@ -1369,8 +1379,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_REQUEST_PROFILE_MESSAGE.formatted(invalidProfileId)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_REQUEST_PROFILE_MESSAGE.formatted(invalidProfileId)] and: "Response should contain error" assert !response.ext?.errors @@ -1417,8 +1427,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_IMP_PROFILE_MESSAGE.formatted(invalidProfile.id)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_IMP_PROFILE_MESSAGE.formatted(invalidProfile.id)] and: "Response should contain error" assert !response.ext?.errors @@ -1457,8 +1467,8 @@ class ProfileSpec extends BaseSpec { def response = pbsWithStoredProfiles.sendAuctionRequest(bidRequest) then: "PBS should emit proper warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == [NO_REQUEST_PROFILE_MESSAGE.formatted(invalidProfileId)] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == [NO_REQUEST_PROFILE_MESSAGE.formatted(invalidProfileId)] and: "Response should contain error" assert !response.ext?.errors @@ -1500,12 +1510,14 @@ class ProfileSpec extends BaseSpec { def "PBS should throw exception when profiles are not configured and request contain profileId"() { when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(requestWithProfile) + def response = defaultPbsService.sendAuctionRequest(requestWithProfile, SC_BAD_REQUEST) then: "PBs should throw error due to invalid profile config" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == INVALID_REQUEST_PREFIX + CONFIG_ERROR_MESSAGE + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == [INVALID_REQUEST_PREFIX + CONFIG_ERROR_MESSAGE] + } where: requestWithProfile << [ @@ -1538,12 +1550,14 @@ class ProfileSpec extends BaseSpec { } when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(requestWithProfile) + def response = defaultPbsService.sendAuctionRequest(requestWithProfile, SC_BAD_REQUEST) then: "PBs should throw error due to invalid profile config" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == INVALID_REQUEST_PREFIX + CONFIG_ERROR_MESSAGE + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == [INVALID_REQUEST_PREFIX + CONFIG_ERROR_MESSAGE] + } cleanup: "Stop and remove pbs container" pbsContainer.stop() diff --git a/src/test/groovy/org/prebid/server/functional/tests/StoredResponseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/StoredResponseSpec.groovy index 0b6f62923c7..c5789655e35 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/StoredResponseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/StoredResponseSpec.groovy @@ -5,16 +5,18 @@ 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.StoredAuctionResponse import org.prebid.server.functional.model.request.auction.StoredBidResponse +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.model.response.auction.SeatBid -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class StoredResponseSpec extends BaseSpec { @@ -146,8 +148,8 @@ class StoredResponseSpec extends BaseSpec { def response = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain warning information" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == ['WARNING: request.imp[0].ext.prebid.storedauctionresponse.seatbidarr is not supported at the imp level'] and: "PBS not send request to bidder" @@ -170,8 +172,8 @@ class StoredResponseSpec extends BaseSpec { assert response.seatbid == [storedAuctionResponse] and: "PBs should emit warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] - assert response.ext?.warnings[ErrorType.PREBID]*.message == + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] + assert response.ext?.warnings[PREBID]*.message == ["no auction. response defined by storedauctionresponse" as String] and: "PBS not send request to bidder" @@ -250,7 +252,7 @@ class StoredResponseSpec extends BaseSpec { def response = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain warning information" - assert response.ext?.warnings[ErrorType.PREBID]*.message.contains('SeatBid can\'t be null in stored response') + assert response.ext?.warnings[PREBID]*.message.contains('SeatBid can\'t be null in stored response') and: "PBS not send request to bidder" assert bidder.getRequestCount(bidRequest.id) == 0 @@ -278,12 +280,14 @@ class StoredResponseSpec extends BaseSpec { bidRequest.imp[0].ext.prebid.storedAuctionResponse = new StoredAuctionResponse(seatBidObject: new SeatBid()) when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS throws an exception" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == 'Invalid request format: Seat can\'t be empty in stored response seatBid' + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ['Invalid request format: Seat can\'t be empty in stored response seatBid'] + } and: "PBS not send request to bidder" assert bidder.getRequestCount(bidRequest.id) == 0 @@ -295,12 +299,14 @@ class StoredResponseSpec extends BaseSpec { bidRequest.imp[0].ext.prebid.storedAuctionResponse = new StoredAuctionResponse(seatBidObject: new SeatBid(bid: [], seat: GENERIC)) when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS throws an exception" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 400 - assert exception.responseBody == 'Invalid request format: There must be at least one bid in stored response seatBid' + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ['Invalid request format: There must be at least one bid in stored response seatBid'] + } and: "PBS not send request to bidder" assert bidder.getRequestCount(bidRequest.id) == 0 diff --git a/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy index d9d337b3c27..986b0e66a44 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy @@ -24,6 +24,7 @@ import org.prebid.server.functional.model.request.auction.StoredAuctionResponse import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.request.auction.Targeting import org.prebid.server.functional.model.request.auction.Video +import org.prebid.server.functional.model.response.BidderErrorCode 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.BidMediaType @@ -32,7 +33,6 @@ import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.model.response.auction.MediaType import org.prebid.server.functional.model.response.auction.Prebid import org.prebid.server.functional.model.response.auction.SeatBid -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig import org.prebid.server.functional.testcontainers.scaffolding.Bidder @@ -41,14 +41,16 @@ import org.prebid.server.functional.util.PBSUtils import java.math.RoundingMode import java.nio.charset.StandardCharsets -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.AccountStatus.ACTIVE 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.WILDCARD import static org.prebid.server.functional.model.config.PriceGranularityType.UNKNOWN +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.model.response.auction.ErrorType.TARGETING import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class TargetingSpec extends BaseSpec { @@ -1159,12 +1161,14 @@ class TargetingSpec extends BaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsWithDefaultTargetingLength.sendAuctionRequest(bidRequest) + def response = pbsWithDefaultTargetingLength.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == 'Invalid request format: Price granularity error: empty granularity definition supplied' + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ['Invalid request format: Price granularity error: empty granularity definition supplied'] + } } def "PBS auction should prioritize price granularity from original request over account config"() { @@ -1333,12 +1337,13 @@ class TargetingSpec extends BaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsWithDefaultTargetingLength.sendAmpRequest(ampRequest) + def response = pbsWithDefaultTargetingLength.sendAmpRequest(ampRequest, SC_BAD_REQUEST) then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == 'Invalid request format: Price granularity error: empty granularity definition supplied' + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage == ['Invalid request format: Price granularity error: empty granularity definition supplied'] + } } def "PBS amp should include price granularity from account config when original request doesn't contain price granularity"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy index 97a0015cea5..94bdba95637 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy @@ -15,7 +15,7 @@ import org.prebid.server.functional.model.response.auction.InterestGroupAuctionI import org.prebid.server.functional.model.response.auction.InterestGroupAuctionSeller import org.prebid.server.functional.model.response.auction.OpenxBidResponse import org.prebid.server.functional.model.response.auction.OpenxBidResponseExt -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils @@ -23,6 +23,7 @@ import spock.lang.Shared import java.time.Instant +import static org.apache.http.HttpStatus.SC_BAD_REQUEST import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.OPENX_ALIAS import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD @@ -33,6 +34,7 @@ import static org.prebid.server.functional.model.request.auction.AuctionEnvironm import static org.prebid.server.functional.model.request.auction.PaaFormat.IAB import static org.prebid.server.functional.model.request.auction.PaaFormat.ORIGINAL import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer class OpenxSpec extends BaseSpec { @@ -438,7 +440,7 @@ class OpenxSpec extends BaseSpec { assert getLogsByText(logs, "ExtIgiIgs with absent impId from bidder: ${OPENX.value}") and: "Bid response should contain warning" - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == ["ExtIgiIgs with absent impId from bidder: ${OPENX.value}" as String] @@ -506,13 +508,16 @@ class OpenxSpec extends BaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + def response = pbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "Request should fail with error" - def exception = thrown(PrebidServerException) - assert exception.responseBody.startsWith("Invalid request format: Error decoding bidRequest: " + - "Cannot deserialize value of type `org.prebid.server.auction.model.PaaFormat` " + - "from String \"invalid\": not one of the values accepted for Enum class: [original, iab]") + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BidderErrorCode.GENERIC] + it.errorMessage.any { it.startsWith("Invalid request format: Error decoding bidRequest: " + + "Cannot deserialize value of type `org.prebid.server.auction.model.PaaFormat` " + + "from String \"invalid\": not one of the values accepted for Enum class: [original, iab]") } + } } def "PBS shouldn't cause error when igs and igb empty array"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy index c0933a238e7..030245ed4a5 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy @@ -5,7 +5,6 @@ import org.prebid.server.functional.model.config.ExecutionPlan import org.prebid.server.functional.model.config.Stage import org.prebid.server.functional.model.response.auction.AnalyticResult import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.model.response.auction.InvocationResult import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy index 82355a47996..791b9ed2fbd 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy @@ -13,6 +13,7 @@ import org.prebid.server.functional.model.request.auction.FetchStatus import org.prebid.server.functional.model.request.auction.PrebidAnalytics import org.prebid.server.functional.model.request.auction.RichmediaFilter import org.prebid.server.functional.model.request.auction.StoredBidResponse +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ModuleActivityName import org.prebid.server.functional.service.PrebidServerService @@ -271,7 +272,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { assert !bidResponse?.ext?.prebid?.analytics?.tags and: "Bid response should contain warning" - assert bidResponse.ext.warnings[PREBID]?.code == [999] + assert bidResponse.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert bidResponse.ext.warnings[PREBID]?.message == ["analytics.options.enableclientdetails not enabled for account"] } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/RuleEngineDeviceSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/RuleEngineDeviceSpec.groovy index 229e54a0ff0..42ebc8ee959 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/RuleEngineDeviceSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/RuleEngineDeviceSpec.groovy @@ -6,7 +6,6 @@ import org.prebid.server.functional.model.pricefloors.Country import org.prebid.server.functional.model.request.auction.Device import org.prebid.server.functional.model.request.auction.DeviceType import org.prebid.server.functional.util.PBSUtils -import spock.lang.RepeatUntilFailure import java.time.Instant diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy index c04e4d263d7..5fab38eecdb 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy @@ -20,6 +20,7 @@ import org.prebid.server.functional.model.request.auction.MultiBid import org.prebid.server.functional.model.request.auction.Native 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.BidderErrorCode 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.BidMediaType @@ -845,7 +846,7 @@ class PriceFloorsAdjustmentSpec extends PriceFloorsBaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=${adjustmentType}, " + "value=${ruleValue}, currency=${currency}] in ${mediaType.value}.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" @@ -996,7 +997,7 @@ class PriceFloorsAdjustmentSpec extends PriceFloorsBaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=${adjustmentType}, " + "value=${adjustmentPrice}, currency=null] in banner.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" @@ -1096,7 +1097,7 @@ class PriceFloorsAdjustmentSpec extends PriceFloorsBaseSpec { and: "Should add a warning when in debug mode" def errorMessage = "bid adjustment from request was invalid: the found rule [adjtype=UNKNOWN, " + "value=$adjustmentPrice, currency=$currency] in banner.generic.* is invalid" as String - assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.code == [BidderErrorCode.GENERIC] assert response.ext.warnings[PREBID]?.message == [errorMessage] and: "Original bid price and currency should be presented in bid.ext" diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy index b569514d0c4..b9da5c12966 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy @@ -4,6 +4,7 @@ import org.prebid.server.functional.model.config.AccountPriceFloorsConfig import org.prebid.server.functional.model.config.PriceFloorsFetch import org.prebid.server.functional.model.pricefloors.PriceFloorData import org.prebid.server.functional.model.request.auction.ImpExtPrebidFloors +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType @@ -207,13 +208,13 @@ class PriceFloorsCurrencySpec extends PriceFloorsBaseSpec { def response = pbsService.sendAuctionRequest(bidRequest) then: "PBS should log an error" - assert response.ext?.errors[ErrorType.GENERIC]*.code == [999] + assert response.ext?.errors[ErrorType.GENERIC]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[ErrorType.GENERIC]*.message == ["Unable to convert from currency $bidRequest.ext.prebid.floors.floorMinCur to desired ad server" + " currency ${floorsResponse.modelGroups[0].currency}" as String] and: "PBS should log a warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["Error occurred while resolving floor for imp: ${bidRequest.imp[0].id}, cause: Unable " + "to convert from currency $requestFloorCur to desired ad server currency $floorsProviderCur"] @@ -402,7 +403,7 @@ class PriceFloorsCurrencySpec extends PriceFloorsBaseSpec { def response = currencyFloorsPbsService.sendAuctionRequest(bidRequest) then: "PBS should log a warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["Error occurred while resolving floor for imp: ${bidRequest.imp[0].id}, cause: Unable " + "to convert from currency $requestFloorCur to desired ad server currency $floorsProviderCur"] @@ -463,7 +464,7 @@ class PriceFloorsCurrencySpec extends PriceFloorsBaseSpec { def response = currencyFloorsPbsService.sendAuctionRequest(bidRequest) then: "PBS should log a warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["imp[].ext.prebid.floors.floorMinCur and ext.prebid.floors.floorMinCur has different values"] diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsEnforcementSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsEnforcementSpec.groovy index cec8bb8fa41..77bc554b221 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsEnforcementSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsEnforcementSpec.groovy @@ -12,6 +12,7 @@ import org.prebid.server.functional.model.request.auction.ExtPrebidPriceFloorEnf import org.prebid.server.functional.model.request.auction.MultiBid import org.prebid.server.functional.model.request.auction.StoredAuctionResponse import org.prebid.server.functional.model.request.auction.Targeting +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType @@ -85,7 +86,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { } and: "PBS should log warning about bid suppression" - assert response.ext?.warnings[ErrorType.ALIAS]*.code == [6] + assert response.ext?.warnings[ErrorType.ALIAS]*.code == [BidderErrorCode.REJECTED_IPF] assert response.ext?.warnings[ErrorType.ALIAS]*.message == ["Bid with id '${aliasBidResponse.seatbid[0].bid[0].id}' was rejected by floor enforcement: " + "price $lowerPrice is below the floor ${floorValue.stripTrailingZeros()}" as String] @@ -136,7 +137,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "PBS should log warning about suppression all bids below the floor value " def impId = bidRequest.imp[0].id - assert response.ext?.warnings[ErrorType.GENERIC]*.code == [6, 6] + assert response.ext?.warnings[ErrorType.GENERIC]*.code == [BidderErrorCode.REJECTED_IPF, BidderErrorCode.REJECTED_IPF] assert response.ext?.warnings[ErrorType.GENERIC]*.message == ["Bid with id '${bidResponse.seatbid[0].bid[1].id}' was rejected by floor enforcement: " + "price ${bidResponse.seatbid[0].bid[1].price} is below the floor ${floorValue.stripTrailingZeros()}" as String, @@ -249,7 +250,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "Response should contain specific code and text in ext.warnings.prebid" verifyAll(bidResponse.ext.warnings[PREBID]) { - it.code == [999] + it.code == [BidderErrorCode.GENERIC] it.message == ["noFloorSignal to bidder generic"] } @@ -370,7 +371,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "Response should contain specific code and text in ext.warnings.prebid" verifyAll(bidResponse.ext.warnings[PREBID]) { - it.code == [999] + it.code == [BidderErrorCode.GENERIC] it.message == ["noFloorSignal to bidder generic"] } @@ -491,7 +492,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "Response should contain specific code and text in ext.warnings.prebid" verifyAll(bidResponse.ext.warnings[PREBID]) { - it.code == [999] + it.code == [BidderErrorCode.GENERIC] it.message == ["noFloorSignal to bidder generic"] } @@ -660,7 +661,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "Response should contain specific code and text in ext.warnings.prebid" verifyAll(bidResponse.ext.warnings[PREBID]) { - it.code == [999] + it.code == [BidderErrorCode.GENERIC] it.message == ["noFloorSignal to bidder generic"] } } @@ -739,7 +740,7 @@ class PriceFloorsEnforcementSpec extends PriceFloorsBaseSpec { and: "Response should contain specific code and text in ext.warnings.prebid" verifyAll(bidResponse.ext.warnings[PREBID]) { - it.code == [999] + it.code == [BidderErrorCode.GENERIC] it.message == ["noFloorSignal to bidder generic"] } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy index b40f6e8cac2..954b12060f9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy @@ -9,6 +9,7 @@ import org.prebid.server.functional.model.request.amp.AmpRequest import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.ExtPrebidFloors import org.prebid.server.functional.model.request.auction.PrebidStoredRequest +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.util.PBSUtils @@ -646,7 +647,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { assert metrics[FETCH_FAILURE_METRIC] == 1 and: "PBS should add single warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE("Price floor data useFetchDataRate must be in range(0-100), but was $requestUseFetchDataRate")] @@ -1400,7 +1401,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { and: "Response should contain warning" def message = "Price floor floorMin must be positive float, but was $invalidFloorMin" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] } @@ -1431,7 +1432,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { and: "Response should contain warning" def message = "Price floor rules should contain at least one model group" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] } @@ -1461,7 +1462,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { assert bidderRequest.imp[0].bidFloor == floorValue and: "Response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(PRICE_FLOOR_VALUES_MISSING)] } @@ -1495,7 +1496,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { assert bidderRequest.imp[0].bidFloor == floorValue and: "Response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(MODEL_WEIGHT_INVALID.formatted(invalidModelWeight))] where: @@ -1537,7 +1538,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { assert bidderRequest.imp[0].bidFloor == floorValue and: "Response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(MODEL_WEIGHT_INVALID.formatted(invalidModelWeight))] where: @@ -1580,7 +1581,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { and: "Response should contain warning" def message = "Price floor root skipRate must be in range(0-100), but was $invalidSkipRate" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] where: @@ -1623,7 +1624,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { and: "Response should contain warning" def message = "Price floor data skipRate must be in range(0-100), but was $invalidSkipRate" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] where: @@ -1665,7 +1666,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { assert bidderRequest.imp[0].bidFloor == floorValue and: "Response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(SKIP_RATE_INVALID.formatted(invalidSkipRate))] where: @@ -1704,7 +1705,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { and: "Response should contain warning" def message = "Price floor modelGroup default must be positive float, but was $invalidDefaultFloorValue" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] } @@ -1776,7 +1777,7 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor rules data must be present" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should not add errors" diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy index b06c2530242..505bdb0fa61 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy @@ -14,6 +14,7 @@ import org.prebid.server.functional.model.request.auction.ExtPrebidFloors import org.prebid.server.functional.model.request.auction.ExtPrebidPriceFloorEnforcement import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.Video +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.MediaType import org.prebid.server.functional.util.PBSUtils @@ -606,7 +607,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor rules number ${getRuleSize(bidRequest)} exceeded its maximum number ${MAX_RULES_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "Alerts.general metrics should be populated" @@ -647,7 +648,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor schema dimensions ${getSchemaSize(bidRequest)} exceeded its maximum number ${MAX_SCHEMA_DIMENSIONS_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "Alerts.general metrics should be populated" @@ -694,7 +695,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor schema dimensions ${getSchemaSize(bidRequest)} exceeded its maximum number ${MAX_SCHEMA_DIMENSIONS_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -747,7 +748,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "Response should includer error warning" def message = "Price floor schema dimensions ${getSchemaSize(bidRequest)} exceeded its maximum number ${MAX_SCHEMA_DIMENSIONS_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS shouldn't log a errors" @@ -788,7 +789,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor schema dimensions ${getSchemaSize(bidRequest)} exceeded its maximum number ${MAX_SCHEMA_DIMENSIONS_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -833,7 +834,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor schema dimensions ${floorSchemaFilesSize} " + "exceeded its maximum number ${MAX_SCHEMA_DIMENSIONS_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -906,7 +907,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor rules number ${getRuleSize(ampStoredRequest)} " + "exceeded its maximum number ${MAX_RULES_SIZE}" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -944,7 +945,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor data skipRate must be in range(0-100), but was $requestSkipRate" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -978,7 +979,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor rules should contain at least one model group" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -1014,7 +1015,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor modelGroup modelWeight must be in range(1-100), but was $requestModelWeight" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -1051,7 +1052,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor modelGroup skipRate must be in range(0-100), but was $requestModelGroupsSkipRate" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log an errors" @@ -1086,7 +1087,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor modelGroup default must be positive float, but was $requestModelGroupsSkipRate" - assert bidResponse.ext?.warnings[PREBID]*.code == [999] + assert bidResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert bidResponse.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" @@ -1126,7 +1127,7 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { then: "PBS should log a warning" def message = "Price floor rules data must be present" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == [WARNING_MESSAGE(message)] and: "PBS should log a errors" diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/CcpaAmpSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/CcpaAmpSpec.groovy index 945ee175ee1..decfc1b27ea 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/CcpaAmpSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/CcpaAmpSpec.groovy @@ -6,6 +6,7 @@ import org.prebid.server.functional.model.config.AccountPrivacyConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.db.StoredRequest import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.util.privacy.BogusConsent import org.prebid.server.functional.util.privacy.CcpaConsent @@ -199,7 +200,7 @@ class CcpaAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[ErrorType.PREBID]*.code == [999] + assert response.ext?.errors[ErrorType.PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[ErrorType.PREBID]*.message == ["CCPA consent $invalidCcpa has invalid format: us_privacy must contain 4 characters" as String] @@ -227,7 +228,7 @@ class CcpaAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[ErrorType.PREBID]*.code == [999] + assert response.ext?.errors[ErrorType.PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[ErrorType.PREBID]*.message == ["Invalid consent_type param passed"] } @@ -249,7 +250,7 @@ class CcpaAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[ErrorType.PREBID]*.code == [999] + assert response.ext?.errors[ErrorType.PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[ErrorType.PREBID]*.message == ["Consent type tcfV1 is no longer supported"] } @@ -273,7 +274,7 @@ class CcpaAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[ErrorType.PREBID]*.code == [999] + assert response.ext?.errors[ErrorType.PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[ErrorType.PREBID]*.message == ["CCPA consent $tcfConsent has invalid format: us_privacy must contain 4 characters" as String] } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy index c2bf06fe50a..1ec89894b3e 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/DsaSpec.groovy @@ -8,6 +8,7 @@ import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Dsa import org.prebid.server.functional.model.request.auction.Dsa as RequestDsa import org.prebid.server.functional.model.request.auction.RegsExt +import org.prebid.server.functional.model.response.BidderErrorCode 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.DsaResponse @@ -15,13 +16,13 @@ import org.prebid.server.functional.model.response.auction.DsaResponse as BidDsa import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.TcfConsent - import static org.prebid.server.functional.model.request.auction.DsaPubRender.PUB_CANT_RENDER import static org.prebid.server.functional.model.request.auction.DsaPubRender.PUB_WILL_RENDER import static org.prebid.server.functional.model.request.auction.DsaRequired.NOT_REQUIRED import static org.prebid.server.functional.model.request.auction.DsaRequired.REQUIRED import static org.prebid.server.functional.model.request.auction.DsaRequired.REQUIRED_PUBLISHER_IS_ONLINE_PLATFORM import static org.prebid.server.functional.model.request.auction.DsaRequired.SUPPORTED +import static org.prebid.server.functional.model.response.BidderErrorCode.INVALID_BID import static org.prebid.server.functional.model.response.auction.BidRejectionReason.RESPONSE_REJECTED_DUE_TO_DSA import static org.prebid.server.functional.model.response.auction.DsaAdRender.ADVERTISER_WILL_RENDER import static org.prebid.server.functional.model.response.auction.DsaAdRender.ADVERTISER_WONT_RENDER @@ -170,7 +171,7 @@ class DsaSpec extends PrivacyBaseSpec { and: "Response should contain an error" def bidId = bidResponse.seatbid[0].bid[0].id - assert response.ext?.warnings[GENERIC]*.code == [5] + assert response.ext?.warnings[GENERIC]*.code == [INVALID_BID] assert response.ext?.warnings[GENERIC]*.message == ["Bid \"$bidId\": DSA object missing when required"] where: @@ -285,7 +286,7 @@ class DsaSpec extends PrivacyBaseSpec { and: "Response should contain an error" def bidId = bidResponse.seatbid[0].bid[0].id - assert response.ext?.warnings[GENERIC]*.code == [5] + assert response.ext?.warnings[GENERIC]*.code == [INVALID_BID] assert response.ext?.warnings[GENERIC]*.message == ["Bid \"$bidId\": DSA object missing when required"] where: @@ -323,7 +324,7 @@ class DsaSpec extends PrivacyBaseSpec { and: "Response should contain an error" def bidId = bidResponse.seatbid[0].bid[0].id - assert response.ext?.warnings[GENERIC]*.code == [5] + assert response.ext?.warnings[GENERIC]*.code == [INVALID_BID] assert response.ext?.warnings[GENERIC]*.message == ["Bid \"$bidId\": DSA object missing when required"] where: @@ -503,7 +504,7 @@ class DsaSpec extends PrivacyBaseSpec { and: "Response should contain an error" def bidId = bidResponse.seatbid[0].bid[0].id - assert response.ext?.warnings[GENERIC]*.code == [5] + assert response.ext?.warnings[GENERIC]*.code == [INVALID_BID] assert response.ext?.warnings[GENERIC]*.message == ["Bid \"$bidId\": ${warningMessage}"] where: @@ -543,7 +544,7 @@ class DsaSpec extends PrivacyBaseSpec { and: "Response should contain an error" def bidId = bidResponse.seatbid[0].bid[0].id - assert response.ext?.warnings[GENERIC]*.code == [5] + assert response.ext?.warnings[GENERIC]*.code == [INVALID_BID] assert response.ext?.warnings[GENERIC]*.message == ["Bid \"$bidId\": ${warningMessage}"] where: diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAmpSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAmpSpec.groovy index 717c9f32d5b..b0fa39c9738 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAmpSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAmpSpec.groovy @@ -13,6 +13,7 @@ import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.DistributionChannel import org.prebid.server.functional.model.request.auction.Regs import org.prebid.server.functional.model.request.auction.RegsExt +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.BogusConsent import org.prebid.server.functional.util.privacy.CcpaConsent @@ -146,7 +147,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message[0].startsWith("Parsing consent string:\"${invalidTcfConsent}\"") where: @@ -173,7 +174,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[PREBID]*.code == [999] + assert response.ext?.errors[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[PREBID]*.message == ["Consent type tcfV1 is no longer supported"] } @@ -197,7 +198,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[PREBID]*.code == [999] + assert response.ext?.errors[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[PREBID]*.message == ["CCPA consent $consentString has invalid format: " + "us_privacy must contain 4 characters"] @@ -223,7 +224,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.errors[PREBID]*.code == [999] + assert response.ext?.errors[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.errors[PREBID]*.message == ["Invalid consent_type param passed"] } @@ -245,7 +246,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAmpRequest(ampRequest) then: "Response should contain error" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message[0] ==~ /Parsing consent string:"$ccpaConsent" - failed.*/ } @@ -388,7 +389,7 @@ class GdprAmpSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAmpRequest(ampRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message == ["Unknown tcfPolicyVersion ${invalidTcfPolicyVersion}, defaulting to gvlSpecificationVersion=3" as String] diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy index 299d911a398..5598df8f645 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy @@ -11,6 +11,7 @@ import org.prebid.server.functional.model.pricefloors.Country import org.prebid.server.functional.model.request.auction.DistributionChannel import org.prebid.server.functional.model.request.auction.Regs import org.prebid.server.functional.model.request.auction.RegsExt +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.BogusConsent @@ -23,7 +24,6 @@ import java.time.Instant import static org.prebid.server.functional.model.ChannelType.PBJS import static org.prebid.server.functional.model.ChannelType.WEB import static org.prebid.server.functional.model.bidder.BidderName.GENERIC - import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.DETAILED import static org.prebid.server.functional.model.config.Purpose.P1 import static org.prebid.server.functional.model.config.Purpose.P2 @@ -336,7 +336,7 @@ class GdprAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]*.code == [999] + assert response.ext?.warnings[ErrorType.PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ErrorType.PREBID]*.message == ["Unknown tcfPolicyVersion ${invalidTcfPolicyVersion}, defaulting to gvlSpecificationVersion=3" as String] diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAmpSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAmpSpec.groovy index ab4d46117ab..169d205b894 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAmpSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAmpSpec.groovy @@ -6,9 +6,10 @@ import org.prebid.server.functional.model.request.amp.ConsentType import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Regs import org.prebid.server.functional.model.request.auction.RegsExt +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.util.PBSUtils -import org.prebid.server.functional.util.privacy.gpp.v2.TcfEuV2Consent import org.prebid.server.functional.util.privacy.gpp.v1.UspV1Consent +import org.prebid.server.functional.util.privacy.gpp.v2.TcfEuV2Consent import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2 import static org.prebid.server.functional.model.request.GppSectionId.USP_V1 @@ -86,7 +87,7 @@ class GppAmpSpec extends PrivacyBaseSpec { assert !bidderRequests.regs.gppSid and: "Repose should contain warning" - assert ampResponse.ext?.warnings[PREBID]*.code == [999] + assert ampResponse.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert ampResponse.ext?.warnings[PREBID]*.message[0].startsWith("Failed to parse gppSid: \'${gppSids}\'") } @@ -107,7 +108,7 @@ class GppAmpSpec extends PrivacyBaseSpec { def response = defaultPbsService.sendAmpRequest(ampRequest) then: "Response should contain warning" - assert response.ext?.warnings[PREBID]*.code == [999] + assert response.ext?.warnings[PREBID]*.code == [BidderErrorCode.GENERIC] assert response.ext?.warnings[PREBID]*.message.every { it.contains("GPP string invalid:") } and: "Bidder request should contain gpp from consent string" diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAuctionSpec.groovy index d0282d48ddd..8506865f1cc 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppAuctionSpec.groovy @@ -4,12 +4,13 @@ import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Regs import org.prebid.server.functional.model.request.auction.RegsExt import org.prebid.server.functional.model.request.auction.User +import org.prebid.server.functional.model.response.BidderErrorCode import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.CcpaConsent import org.prebid.server.functional.util.privacy.TcfConsent -import org.prebid.server.functional.util.privacy.gpp.v2.TcfEuV2Consent import org.prebid.server.functional.util.privacy.gpp.v1.UspV1Consent +import org.prebid.server.functional.util.privacy.gpp.v2.TcfEuV2Consent import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2 import static org.prebid.server.functional.model.request.GppSectionId.USP_V1 @@ -69,7 +70,7 @@ class GppAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["GPP scope does not match TCF2 scope"] @@ -92,7 +93,7 @@ class GppAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["GPP scope does not match TCF2 scope"] @@ -117,7 +118,7 @@ class GppAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } .any { it.contains("GPP string invalid:") } @@ -161,7 +162,7 @@ class GppAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["GPP TCF2 string does not match user.consent"] @@ -222,7 +223,7 @@ class GppAuctionSpec extends PrivacyBaseSpec { def response = privacyPbsService.sendAuctionRequest(bidRequest) then: "Bid response should contain warning" - assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [999] + assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.code } == [BidderErrorCode.GENERIC] assert response.ext?.warnings[ErrorType.PREBID]?.collect { it.message } == ["USP string does not match regs.us_privacy"] diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppFetchBidActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppFetchBidActivitiesSpec.groovy index d292bd9e6f1..5274454f7ef 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppFetchBidActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppFetchBidActivitiesSpec.groovy @@ -20,7 +20,6 @@ import org.prebid.server.functional.model.request.auction.Condition import org.prebid.server.functional.model.request.auction.Device import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.RegsExt -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.gpp.v1.UsCaV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsCoV1Consent @@ -32,7 +31,7 @@ import org.prebid.server.functional.util.privacy.gpp.v2.UsNatV2Consent import java.time.Instant -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED import static org.prebid.server.functional.model.config.ConfigCase.CAMEL_CASE import static org.prebid.server.functional.model.config.ConfigCase.KEBAB_CASE import static org.prebid.server.functional.model.config.ConfigCase.SNAKE_CASE @@ -79,6 +78,9 @@ import static org.prebid.server.functional.model.request.auction.PrivacyModule.I import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_CUSTOM_LOGIC import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_GENERAL import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.util.privacy.model.State.ALABAMA import static org.prebid.server.functional.util.privacy.model.State.ONTARIO @@ -814,12 +816,14 @@ class GppFetchBidActivitiesSpec extends PrivacyBaseSpec { accountDao.save(account) when: "PBS processes auction requests" - activityPbsService.sendAuctionRequest(genericBidRequest) + def response = activityPbsService.sendAuctionRequest(genericBidRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS auction call when privacy regulation don't match custom requirement should call to bidder"() { @@ -1606,12 +1610,13 @@ class GppFetchBidActivitiesSpec extends PrivacyBaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - activityPbsService.sendAmpRequest(ampRequest) + def response = activityPbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS amp call when privacy regulation don't match custom requirement should call to bidder"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitEidsActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitEidsActivitiesSpec.groovy index 1db77ef0b90..69b029913d7 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitEidsActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitEidsActivitiesSpec.groovy @@ -20,7 +20,6 @@ import org.prebid.server.functional.model.request.auction.Condition import org.prebid.server.functional.model.request.auction.Device import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.RegsExt -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.gpp.v1.UsCaV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsCoV1Consent @@ -32,7 +31,7 @@ import org.prebid.server.functional.util.privacy.gpp.v2.UsNatV2Consent import java.time.Instant -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.AND import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.OR import static org.prebid.server.functional.model.config.UsNationalPrivacySection.CHILD_CONSENTS_BELOW_13 @@ -76,7 +75,9 @@ import static org.prebid.server.functional.model.request.auction.PrivacyModule.I import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_CUSTOM_LOGIC import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_GENERAL import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.util.privacy.model.State.ALABAMA import static org.prebid.server.functional.util.privacy.model.State.ONTARIO @@ -1123,12 +1124,14 @@ class GppTransmitEidsActivitiesSpec extends PrivacyBaseSpec { accountDao.save(account) when: "PBS processes auction requests" - activityPbsService.sendAuctionRequest(bidRequest) + def response = activityPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS auction call when privacy regulation don't match custom requirement should leave EIDS fields in request"() { @@ -2399,12 +2402,13 @@ class GppTransmitEidsActivitiesSpec extends PrivacyBaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - activityPbsService.sendAmpRequest(ampRequest) + def response = activityPbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS amp call when privacy regulation don't match custom requirement should leave EIDS fields in request"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitPreciseGeoActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitPreciseGeoActivitiesSpec.groovy index e3be1b13e98..50c7d1899f2 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitPreciseGeoActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitPreciseGeoActivitiesSpec.groovy @@ -19,7 +19,6 @@ import org.prebid.server.functional.model.request.auction.AllowActivities import org.prebid.server.functional.model.request.auction.Condition import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.RegsExt -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.gpp.v1.UsCaV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsCoV1Consent @@ -31,7 +30,7 @@ import org.prebid.server.functional.util.privacy.gpp.v2.UsNatV2Consent import java.time.Instant -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.AND import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.OR import static org.prebid.server.functional.model.config.UsNationalPrivacySection.CHILD_CONSENTS_BELOW_13 @@ -75,6 +74,9 @@ import static org.prebid.server.functional.model.request.auction.PrivacyModule.I import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_CUSTOM_LOGIC import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_GENERAL import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR import static org.prebid.server.functional.util.privacy.model.State.ALABAMA import static org.prebid.server.functional.util.privacy.model.State.ONTARIO @@ -1459,12 +1461,14 @@ class GppTransmitPreciseGeoActivitiesSpec extends PrivacyBaseSpec { accountDao.save(account) when: "PBS processes auction requests" - activityPbsService.sendAuctionRequest(bidRequest) + def response = activityPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS auction call when privacy regulation don't match custom requirement should not round lat/lon data"() { @@ -2808,12 +2812,13 @@ class GppTransmitPreciseGeoActivitiesSpec extends PrivacyBaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - activityPbsService.sendAmpRequest(ampRequest) + def response = activityPbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS amp call when privacy regulation don't match custom requirement should not round lat/lon data in request"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitUfpdActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitUfpdActivitiesSpec.groovy index b648a4fe91c..daba3f79897 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitUfpdActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppTransmitUfpdActivitiesSpec.groovy @@ -15,6 +15,7 @@ import org.prebid.server.functional.model.privacy.gpp.MspaMode import org.prebid.server.functional.model.privacy.gpp.Notice import org.prebid.server.functional.model.privacy.gpp.OptOut import org.prebid.server.functional.model.privacy.gpp.UsNationalV1ChildSensitiveData +import org.prebid.server.functional.model.privacy.gpp.UsNationalV1SensitiveData import org.prebid.server.functional.model.privacy.gpp.UsNationalV2ChildSensitiveData import org.prebid.server.functional.model.privacy.gpp.UsNationalV2SensitiveData import org.prebid.server.functional.model.request.amp.AmpRequest @@ -25,7 +26,8 @@ import org.prebid.server.functional.model.request.auction.Condition import org.prebid.server.functional.model.request.auction.Device import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.RegsExt -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.auction.ErrorType +import org.prebid.server.functional.model.response.auction.NoBidResponse import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.gpp.v1.UsCaV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsCoV1Consent @@ -33,12 +35,11 @@ import org.prebid.server.functional.util.privacy.gpp.v1.UsCtV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsNatV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsUtV1Consent import org.prebid.server.functional.util.privacy.gpp.v1.UsVaV1Consent -import org.prebid.server.functional.model.privacy.gpp.UsNationalV1SensitiveData import org.prebid.server.functional.util.privacy.gpp.v2.UsNatV2Consent import java.time.Instant -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.AND import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.OR import static org.prebid.server.functional.model.config.UsNationalPrivacySection.CHILD_CONSENTS_BELOW_13 @@ -82,6 +83,7 @@ import static org.prebid.server.functional.model.request.auction.PrivacyModule.I import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_CUSTOM_LOGIC import static org.prebid.server.functional.model.request.auction.PrivacyModule.IAB_US_GENERAL import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.util.privacy.model.State.ALABAMA import static org.prebid.server.functional.util.privacy.model.State.ONTARIO @@ -1653,12 +1655,14 @@ class GppTransmitUfpdActivitiesSpec extends PrivacyBaseSpec { accountDao.save(account) when: "PBS processes auction requests" - activityPbsService.sendAuctionRequest(bidRequest) + def response = activityPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == NoBidResponse.UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS auction call when privacy regulation don't match custom requirement should leave UFPD fields in request"() { @@ -3389,12 +3393,13 @@ class GppTransmitUfpdActivitiesSpec extends PrivacyBaseSpec { storedRequestDao.save(storedRequest) when: "PBS processes amp request" - activityPbsService.sendAmpRequest(ampRequest) + def response = activityPbsService.sendAmpRequest(ampRequest, SC_UNAUTHORIZED) then: "Response should contain error" - def error = thrown(PrebidServerException) - assert error.statusCode == UNAUTHORIZED.code() - assert error.responseBody == "Unauthorized account id: ${accountId}" + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS amp call when privacy regulation don't match custom requirement should leave UFPD fields in request"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/storage/AccountS3Spec.groovy b/src/test/groovy/org/prebid/server/functional/tests/storage/AccountS3Spec.groovy index 3a87be7b9e7..0fa0eb101be 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/storage/AccountS3Spec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/storage/AccountS3Spec.groovy @@ -1,15 +1,18 @@ package org.prebid.server.functional.tests.storage +import org.apache.http.HttpStatus import org.prebid.server.functional.model.AccountStatus import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.service.S3Service import org.prebid.server.functional.testcontainers.PbsServiceFactory import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED +import static org.prebid.server.functional.model.response.BidderErrorCode.BAD_INPUT +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class AccountS3Spec extends StorageBaseSpec { @@ -51,12 +54,14 @@ class AccountS3Spec extends StorageBaseSpec { s3Service.uploadAccount(DEFAULT_BUCKET, account) when: "PBS processes auction request" - s3StorageAccountPbsService.sendAuctionRequest(bidRequest) + def response = s3StorageAccountPbsService.sendAuctionRequest(bidRequest, HttpStatus.SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Account $accountId is inactive" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Account $accountId is inactive"] + } } def "PBS should throw exception when account id isn't match with bid request account id"() { @@ -73,12 +78,14 @@ class AccountS3Spec extends StorageBaseSpec { s3Service.uploadAccount(DEFAULT_BUCKET, account, accountId) when: "PBS processes auction request" - s3StorageAccountPbsService.sendAuctionRequest(bidRequest) + def response = s3StorageAccountPbsService.sendAuctionRequest(bidRequest, HttpStatus.SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS should throw exception when account is invalid in S3 storage json file"() { @@ -92,12 +99,14 @@ class AccountS3Spec extends StorageBaseSpec { s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_ACCOUNT_DIR}/${accountId}.json") when: "PBS processes auction request" - s3StorageAccountPbsService.sendAuctionRequest(bidRequest) + def response = s3StorageAccountPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } def "PBS should throw exception when account is not present in S3 storage and valid account enforced"() { @@ -108,11 +117,13 @@ class AccountS3Spec extends StorageBaseSpec { } when: "PBS processes auction request" - s3StorageAccountPbsService.sendAuctionRequest(bidRequest) + def response = s3StorageAccountPbsService.sendAuctionRequest(bidRequest, SC_UNAUTHORIZED) then: "PBS should reject the entire auction" - def exception = thrown(PrebidServerException) - assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Unauthorized account id: ${accountId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [BAD_INPUT] + it.errorMessage == ["Unauthorized account id: ${accountId}"] + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/storage/AmpS3Spec.groovy b/src/test/groovy/org/prebid/server/functional/tests/storage/AmpS3Spec.groovy index cf5e68bbc90..15e0e83ea50 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/storage/AmpS3Spec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/storage/AmpS3Spec.groovy @@ -1,15 +1,17 @@ package org.prebid.server.functional.tests.storage +import org.apache.http.HttpStatus 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.BidRequest import org.prebid.server.functional.model.request.auction.Site -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.service.S3Service import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST +import static org.prebid.server.functional.model.response.BidderErrorCode.GENERIC class AmpS3Spec extends StorageBaseSpec { @@ -63,13 +65,14 @@ class AmpS3Spec extends StorageBaseSpec { s3Service.uploadStoredRequest(DEFAULT_BUCKET, storedRequest, ampRequest.tagId) when: "PBS processes amp request" - s3StoragePbsService.sendAmpRequest(ampRequest) + def response = s3StoragePbsService.sendAmpRequest(ampRequest, SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "No stored request found for id: ${ampRequest.tagId}" + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "No stored request found for id: ${ampRequest.tagId}"] + } } def "PBS should throw exception when trying to take parameters from request where id isn't match with stored request id"() { @@ -88,13 +91,14 @@ class AmpS3Spec extends StorageBaseSpec { s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_REQUEST_DIR}/${ampRequest.tagId}.json") when: "PBS processes amp request" - s3StoragePbsService.sendAmpRequest(ampRequest) + def response = s3StoragePbsService.sendAmpRequest(ampRequest, HttpStatus.SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "Can't parse Json for stored request with id ${ampRequest.tagId}" + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "Can't parse Json for stored request with id ${ampRequest.tagId}"] + } } def "PBS should throw an exception when trying to take parameters from stored request on S3 service that do not exist"() { @@ -104,12 +108,13 @@ class AmpS3Spec extends StorageBaseSpec { } when: "PBS processes amp request" - s3StoragePbsService.sendAmpRequest(ampRequest) + def response = s3StoragePbsService.sendAmpRequest(ampRequest, HttpStatus.SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "No stored request found for id: ${ampRequest.tagId}" + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "No stored request found for id: ${ampRequest.tagId}"] + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/storage/AuctionS3Spec.groovy b/src/test/groovy/org/prebid/server/functional/tests/storage/AuctionS3Spec.groovy index 51d39dd5af9..2aea9c135f1 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/storage/AuctionS3Spec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/storage/AuctionS3Spec.groovy @@ -1,16 +1,19 @@ package org.prebid.server.functional.tests.storage +import org.apache.http.HttpStatus import org.prebid.server.functional.model.db.StoredImp 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.PrebidStoredRequest import org.prebid.server.functional.model.request.auction.SecurityLevel -import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.model.response.auction.ErrorType +import org.prebid.server.functional.model.response.auction.NoBidResponse import org.prebid.server.functional.service.S3Service import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST +import static org.prebid.server.functional.model.response.BidderErrorCode.GENERIC class AuctionS3Spec extends StorageBaseSpec { @@ -63,13 +66,15 @@ class AuctionS3Spec extends StorageBaseSpec { s3Service.uploadStoredImp(DEFAULT_BUCKET, storedImp, storedRequestId) when: "Requesting PBS auction" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "No stored impression found for id: ${storedRequestId}" + assert response.noBidResponse == NoBidResponse.UNKNOWN_ERROR + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "No stored impression found for id: ${storedRequestId}"] + } } def "PBS should throw exception when trying to populate imp[0].secure from invalid imp stored request on S3 service"() { @@ -86,13 +91,15 @@ class AuctionS3Spec extends StorageBaseSpec { s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_IMPS_DIR}/${storedRequestId}.json" ) when: "Requesting PBS auction" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest, HttpStatus.SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "Can't parse Json for stored request with id ${storedRequestId}" + assert response.noBidResponse == NoBidResponse.UNKNOWN_ERROR + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "Can't parse Json for stored request with id ${storedRequestId}"] + } } def "PBS should throw exception when trying to populate imp[0].secure from unexciting imp stored request on S3 service"() { @@ -106,12 +113,14 @@ class AuctionS3Spec extends StorageBaseSpec { } when: "Requesting PBS auction" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest, HttpStatus.SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Stored request processing failed: " + - "No stored impression found for id: ${storedRequestId}" + assert response.noBidResponse == NoBidResponse.UNKNOWN_ERROR + verifyAll(response.ext.errors[ErrorType.PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Stored request processing failed: " + + "No stored impression found for id: ${storedRequestId}"] + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/storage/StoredResponseS3Spec.groovy b/src/test/groovy/org/prebid/server/functional/tests/storage/StoredResponseS3Spec.groovy index e07b5b71f2e..ebbf10f7fcd 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/storage/StoredResponseS3Spec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/storage/StoredResponseS3Spec.groovy @@ -4,12 +4,14 @@ import org.prebid.server.functional.model.db.StoredResponse import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.StoredAuctionResponse import org.prebid.server.functional.model.response.auction.SeatBid -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.S3Service import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static org.apache.http.HttpStatus.SC_BAD_REQUEST +import static org.prebid.server.functional.model.response.BidderErrorCode.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID +import static org.prebid.server.functional.model.response.auction.NoBidResponse.UNKNOWN_ERROR class StoredResponseS3Spec extends StorageBaseSpec { @@ -54,13 +56,15 @@ class StoredResponseS3Spec extends StorageBaseSpec { s3Service.uploadStoredResponse(DEFAULT_BUCKET, storedResponse, storedResponseId as String) when: "PBS processes auction request" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Failed to fetch stored auction response for " + - "impId = ${bidRequest.imp[0].id} and storedAuctionResponse id = ${storedResponseId}." + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Failed to fetch stored auction response for " + + "impId = ${bidRequest.imp[0].id} and storedAuctionResponse id = ${storedResponseId}."] + } } def "PBS should throw request format exception when invalid stored auction response defined in S3 storage"() { @@ -73,12 +77,14 @@ class StoredResponseS3Spec extends StorageBaseSpec { s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_RESPONSE_DIR}/${storedResponseId}.json") when: "PBS processes auction request" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest, SC_BAD_REQUEST) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Can't parse Json for stored response with id ${storedResponseId}" + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Can't parse Json for stored response with id ${storedResponseId}"] + } } def "PBS should throw request format exception when stored auction response defined in request but not defined in S3 storage"() { @@ -88,12 +94,14 @@ class StoredResponseS3Spec extends StorageBaseSpec { bidRequest.imp[0].ext.prebid.storedAuctionResponse = new StoredAuctionResponse(id: storedResponseId) when: "PBS processes auction request" - s3StoragePbsService.sendAuctionRequest(bidRequest) + def response = s3StoragePbsService.sendAuctionRequest(bidRequest) then: "PBS should throw request format error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "Invalid request format: Failed to fetch stored auction response for " + - "impId = ${bidRequest.imp[0].id} and storedAuctionResponse id = ${storedResponseId}." + assert response.noBidResponse == UNKNOWN_ERROR + verifyAll(response.ext.errors[PREBID]) { + it.code == [GENERIC] + it.errorMessage == ["Invalid request format: Failed to fetch stored auction response for " + + "impId = ${bidRequest.imp[0].id} and storedAuctionResponse id = ${storedResponseId}."] + } } }