Skip to content

Commit

Permalink
Test: Price floors max rules dimensions (#3646)
Browse files Browse the repository at this point in the history
* Add functional tests for price floors max rules dimensions
  • Loading branch information
marki1an authored Jan 8, 2025
1 parent 7b9fdd4 commit 4097c12
Show file tree
Hide file tree
Showing 7 changed files with 441 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class AccountPriceFloorsConfig {
Boolean adjustForBidAdjustment
Boolean enforceDealFloors
Boolean useDynamicData
Long maxRules
Long maxSchemaDims

@JsonProperty("enforce_floors_rate")
Integer enforceFloorsRateSnakeCase
Expand All @@ -24,4 +26,8 @@ class AccountPriceFloorsConfig {
Boolean enforceDealFloorsSnakeCase
@JsonProperty("use_dynamic_data")
Boolean useDynamicDataSnakeCase
@JsonProperty("max_rules")
Long maxRulesSnakeCase
@JsonProperty("max_schema_dims")
Long maxSchemaDimsSnakeCase
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ class PriceFloorsFetch {
Integer periodSec
@JsonProperty("period_sec")
Integer periodSecSnakeCase
Integer maxSchemaDims
@JsonProperty("max_schema_dims")
Integer maxSchemaDimsSnakeCase
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ExtPrebidFloors {
ExtPrebidPriceFloorEnforcement enforcement
Integer skipRate
PriceFloorData data
Long maxSchemaDims

static ExtPrebidFloors getExtPrebidFloors() {
new ExtPrebidFloors(floorMin: FLOOR_MIN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,16 @@ abstract class PriceFloorsBaseSpec extends BaseSpec {
maxRules: 0,
maxFileSizeKb: 200,
maxAgeSec: 86400,
periodSec: 3600)
periodSec: 3600,
maxSchemaDims: 5)
def floors = new AccountPriceFloorsConfig(enabled: true,
fetch: fetch,
enforceFloorsRate: 100,
enforceDealFloors: true,
adjustForBidAdjustment: true,
useDynamicData: true)
useDynamicData: true,
maxRules: 0,
maxSchemaDims: 3)
new AccountConfig(auction: new AccountAuctionConfig(priceFloors: floors))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1299,8 +1299,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor floorMin " +
"must be positive float, but was $invalidFloorMin "]
["Failed to parse price floors from request, with a reason: Price floor floorMin " +
"must be positive float, but was $invalidFloorMin"]
}

def "PBS should validate rules from request when request doesn't contain modelGroups"() {
Expand All @@ -1327,8 +1327,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor rules " +
"should contain at least one model group "]
["Failed to parse price floors from request, with a reason: Price floor rules " +
"should contain at least one model group"]
}

def "PBS should validate rules from request when request doesn't contain values"() {
Expand All @@ -1355,8 +1355,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor rules values " +
"can't be null or empty, but were null "]
["Failed to parse price floors from request, with a reason: Price floor rules values " +
"can't be null or empty, but were null"]
}

def "PBS should validate rules from request when modelWeight from request is invalid"() {
Expand Down Expand Up @@ -1387,8 +1387,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor modelGroup modelWeight " +
"must be in range(1-100), but was $invalidModelWeight "]
["Failed to parse price floors from request, with a reason: Price floor modelGroup modelWeight " +
"must be in range(1-100), but was $invalidModelWeight"]
where:
invalidModelWeight << [0, MAX_MODEL_WEIGHT + 1]
}
Expand Down Expand Up @@ -1426,8 +1426,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor modelGroup modelWeight " +
"must be in range(1-100), but was $invalidModelWeight "]
["Failed to parse price floors from request, with a reason: Price floor modelGroup modelWeight " +
"must be in range(1-100), but was $invalidModelWeight"]

where:
invalidModelWeight << [0, MAX_MODEL_WEIGHT + 1]
Expand Down Expand Up @@ -1466,8 +1466,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor root skipRate " +
"must be in range(0-100), but was $invalidSkipRate "]
["Failed to parse price floors from request, with a reason: Price floor root skipRate " +
"must be in range(0-100), but was $invalidSkipRate"]

where:
invalidSkipRate << [SKIP_RATE_MIN - 1, SKIP_RATE_MAX + 1]
Expand Down Expand Up @@ -1506,8 +1506,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor data skipRate " +
"must be in range(0-100), but was $invalidSkipRate "]
["Failed to parse price floors from request, with a reason: Price floor data skipRate " +
"must be in range(0-100), but was $invalidSkipRate"]

where:
invalidSkipRate << [SKIP_RATE_MIN - 1, SKIP_RATE_MAX + 1]
Expand Down Expand Up @@ -1546,8 +1546,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor modelGroup skipRate " +
"must be in range(0-100), but was $invalidSkipRate "]
["Failed to parse price floors from request, with a reason: Price floor modelGroup skipRate " +
"must be in range(0-100), but was $invalidSkipRate"]

where:
invalidSkipRate << [SKIP_RATE_MIN - 1, SKIP_RATE_MAX + 1]
Expand Down Expand Up @@ -1582,8 +1582,8 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
and: "Response should contain error"
assert response.ext?.errors[PREBID]*.code == [999]
assert response.ext?.errors[PREBID]*.message ==
["Failed to parse price floors from request, with a reason : Price floor modelGroup default " +
"must be positive float, but was $invalidDefaultFloorValue "]
["Failed to parse price floors from request, with a reason: Price floor modelGroup default " +
"must be positive float, but was $invalidDefaultFloorValue"]
}

def "PBS should not invalidate previously good fetched data when floors provider return invalid data"() {
Expand Down Expand Up @@ -2046,6 +2046,91 @@ class PriceFloorsFetchingSpec extends PriceFloorsBaseSpec {
}
}

def "PBS should validate fetch.max-schema-dims from account config and not reject entire auction"() {
given: "Default BidRequest"
def bidRequest = BidRequest.defaultBidRequest

and: "Account with enabled fetch, maxSchemaDims in the DB"
def account = getAccountWithEnabledFetch(bidRequest.accountId).tap {
config.auction.priceFloors.fetch.maxSchemaDims = maxSchemaDims
config.auction.priceFloors.fetch.maxSchemaDimsSnakeCase = maxSchemaDimsSnakeCase
}
accountDao.save(account)

when: "PBS processes auction request"
def response = floorsPbsService.sendAuctionRequest(bidRequest)

then: "Metric alerts.account_config.ACCOUNT.price-floors should be update"
def metrics = floorsPbsService.sendCollectedMetricsRequest()
assert metrics[INVALID_CONFIG_METRIC(bidRequest.accountId) as String] == 1

and: "PBS floors validation failure should not reject the entire auction"
assert !response.seatbid?.isEmpty()

where:
maxSchemaDims | maxSchemaDimsSnakeCase
null | PBSUtils.randomNegativeNumber
null | PBSUtils.getRandomNumber(20)
PBSUtils.randomNegativeNumber | null
PBSUtils.getRandomNumber(20) | null
}

def "PBS should validate price-floor.max-rules from account config and not reject entire auction"() {
given: "Default BidRequest"
def bidRequest = BidRequest.defaultBidRequest

and: "Account with enabled fetch, maxRules in the DB"
def account = getAccountWithEnabledFetch(bidRequest.accountId).tap {
config.auction.priceFloors.maxRules = maxRules
config.auction.priceFloors.maxRulesSnakeCase = maxRulesSnakeCase
}
accountDao.save(account)

when: "PBS processes auction request"
def response = floorsPbsService.sendAuctionRequest(bidRequest)

then: "Metric alerts.account_config.ACCOUNT.price-floors should be update"
def metrics = floorsPbsService.sendCollectedMetricsRequest()
assert metrics[INVALID_CONFIG_METRIC(bidRequest.accountId) as String] == 1

and: "PBS floors validation failure should not reject the entire auction"
assert !response.seatbid?.isEmpty()

where:
maxRules | maxRulesSnakeCase
null | PBSUtils.randomNegativeNumber
PBSUtils.randomNegativeNumber | null
}

def "PBS should validate price-floor.max-schema-dims from account config and not reject entire auction"() {
given: "Default BidRequest"
def bidRequest = BidRequest.defaultBidRequest

and: "Account with enabled fetch, maxSchemaDims in the DB"
def account = getAccountWithEnabledFetch(bidRequest.accountId).tap {
config.auction.priceFloors.maxSchemaDims = maxSchemaDims
config.auction.priceFloors.maxSchemaDimsSnakeCase = maxSchemaDimsSnakeCase
}
accountDao.save(account)

when: "PBS processes auction request"
def response = floorsPbsService.sendAuctionRequest(bidRequest)

then: "Metric alerts.account_config.ACCOUNT.price-floors should be update"
def metrics = floorsPbsService.sendCollectedMetricsRequest()
assert metrics[INVALID_CONFIG_METRIC(bidRequest.accountId) as String] == 1

and: "PBS floors validation failure should not reject the entire auction"
assert !response.seatbid?.isEmpty()

where:
maxSchemaDims | maxSchemaDimsSnakeCase
null | PBSUtils.randomNegativeNumber
null | PBSUtils.getRandomNumber(20)
PBSUtils.randomNegativeNumber | null
PBSUtils.getRandomNumber(20) | null
}

static int convertKilobyteSizeToByte(int kilobyteSize) {
kilobyteSize * 1024
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,8 @@ class PriceFloorsRulesSpec extends PriceFloorsBaseSpec {

where:
bidRequest | bothFloorValue | bannerFloorValue | videoFloorValue
bidRequestWithMultipleMediaTypes | 0.6 | PBSUtils.randomFloorValue |
PBSUtils.randomFloorValue
BidRequest.defaultBidRequest | PBSUtils.randomFloorValue | 0.6 |
PBSUtils.randomFloorValue
bidRequestWithMultipleMediaTypes | 0.6 | PBSUtils.randomFloorValue | PBSUtils.randomFloorValue
BidRequest.defaultBidRequest | PBSUtils.randomFloorValue | 0.6 | PBSUtils.randomFloorValue
BidRequest.defaultVideoRequest | PBSUtils.randomFloorValue | PBSUtils.randomFloorValue | 0.6
}

Expand Down
Loading

0 comments on commit 4097c12

Please sign in to comment.