From 5faab3cd167032e4db13b61cb765b2f9c2adda7b Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Mon, 3 Feb 2025 18:54:36 +0200 Subject: [PATCH 1/3] Add functional tests for GPP USNat v2 --- .../model/config/AccountGppConfig.groovy | 1 + .../model/response/auction/And.groovy | 6 + .../tests/privacy/ActivityTraceLogSpec.groovy | 221 +++++++++++++++++- 3 files changed, 226 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountGppConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountGppConfig.groovy index add9834d5c5..bb4e0ab0b74 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountGppConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountGppConfig.groovy @@ -8,5 +8,6 @@ class AccountGppConfig { PrivacyModule code Boolean enabled + Integer skipRate GppModuleConfig config } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy index 4072d3e1f62..4928d7ece87 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy @@ -1,11 +1,17 @@ package org.prebid.server.functional.model.response.auction +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.EqualsAndHashCode import groovy.transform.ToString @ToString(includeNames = true, ignoreNulls = true) @EqualsAndHashCode +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy) class And { List and + String privacyModule + String skipped + String result } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy index e0c3b279200..ae5983048f3 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy @@ -24,6 +24,7 @@ import static org.prebid.server.functional.model.pricefloors.Country.USA import static org.prebid.server.functional.model.request.GppSectionId.US_CA_V1 import static org.prebid.server.functional.model.request.GppSectionId.US_CO_V1 import static org.prebid.server.functional.model.request.auction.ActivityType.FETCH_BIDS +import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_EIDS import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_PRECISE_GEO import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_TID import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_UFPD @@ -42,6 +43,9 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { private static final def PROCESSING_ACTIVITY_TRACE = ["Processing rule."] + private final static Integer MIN_PERCENT_AB = 0 + private final static Integer MAX_PERCENT_AB = 100 + def "PBS auction shouldn't log info about activity in response when ext.prebid.trace=null"() { given: "Default basic generic BidRequest" def accountId = PBSUtils.randomNumber as String @@ -398,10 +402,223 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { allow << [false, true] } - private List getActivityByName(List activityInfrastructures, - ActivityType activity) { + def "PBS auction should log info about activity in response when ext.prebid.trace=verbose and skipRate=#skipRate"() { + given: "Default bid request" + def accountId = PBSUtils.randomNumber as String + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.trace = VERBOSE + device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) + regs.ext = new RegsExt(gpc: PBSUtils.randomString) + regs.gppSid = [US_CA_V1.intValue] + regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() + setAccountId(accountId) + } + + and: "Set up activities" + def gpc = PBSUtils.randomString + def condition = Condition.baseCondition.tap { + it.gpc = gpc + it.geo = [CAN.withState(ARIZONA)] + } + def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { + it.privacyRegulation = [IAB_US_GENERAL] + } + def activity = Activity.getDefaultActivity([activityRule]) + def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + + and: "Account gpp configuration" + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) + + and: "Save account with allow activities setup" + def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) + accountDao.save(account) + + when: "PBS processes auction requests" + def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) + + then: "Bid response should contain verbose info in debug" + def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure + def ruleConfigurations = findProcessingRule(infrastructure, FETCH_BIDS).ruleConfiguration.and + assert ruleConfigurations.size() == 1 + assert ruleConfigurations.first.and.every { it != null } + + and: "Should not contain information that module was skipped" + verifyAll(ruleConfigurations.first) { + !it.privacyModule + !it.skipped + !it.result + } + + where: + skipRate << [null, MIN_PERCENT_AB] + } + + def "PBS auction should log info about module skip in response when ext.prebid.trace=verbose and skipRate is max"() { + given: "Default bid request" + def accountId = PBSUtils.randomNumber as String + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.trace = VERBOSE + device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) + regs.ext = new RegsExt(gpc: PBSUtils.randomString) + regs.gppSid = [US_CA_V1.intValue] + regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() + setAccountId(accountId) + } + + and: "Set up activities" + def gpc = PBSUtils.randomString + def condition = Condition.baseCondition.tap { + it.gpc = gpc + it.geo = [CAN.withState(ARIZONA)] + } + def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { + it.privacyRegulation = [IAB_US_GENERAL] + } + def activity = Activity.getDefaultActivity([activityRule], defaultAction) + def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + + and: "Account gpp configuration" + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: MAX_PERCENT_AB) + + and: "Save account with allow activities setup" + def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) + accountDao.save(account) + + when: "PBS processes auction requests" + def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) + + then: "Bid response should not contain verbose info in debug" + def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure + def ruleConfigurations = findProcessingRule(infrastructure, FETCH_BIDS).ruleConfiguration.and + assert ruleConfigurations.size() == 1 + assert ruleConfigurations.first.and.every { it == null } + + and: "Should contain information that module was skipped" + verifyAll(ruleConfigurations.first) { + it.privacyModule == 'iab.usgeneral' + it.skipped == 'true' + it.result == 'ABSTAIN' + } + + where: + defaultAction << [false, true] + } + + def "PBS auction should log consistently for each activity about skips modules in response"() { + given: "Default bid request" + def accountId = PBSUtils.randomNumber as String + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.trace = VERBOSE + device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) + regs.ext = new RegsExt(gpc: PBSUtils.randomString) + regs.gppSid = [US_CA_V1.intValue] + regs.gpp = new UsNatV1Consent.Builder().build() + setAccountId(accountId) + } + + and: "Set up activities" + def gpc = PBSUtils.randomString + def condition = Condition.baseCondition.tap { + it.gpc = gpc + it.geo = [CAN.withState(ARIZONA)] + } + def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { + it.privacyRegulation = [IAB_US_GENERAL] + } + def activity = Activity.getDefaultActivity([activityRule]) + def activities = new AllowActivities( + syncUser: activity, + fetchBids: activity, + enrichUfpd: activity, + reportAnalytics: activity, + transmitUfpd: activity, + transmitEids: activity, + transmitPreciseGeo: activity, + transmitTid: activity, + ) + + and: "Account gpp configuration" + def skipRate = PBSUtils.getRandomNumber(MIN_PERCENT_AB, MAX_PERCENT_AB) + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) + + and: "Save account with allow activities setup" + def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) + accountDao.save(account) + + when: "PBS processes auction requests" + def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) + + then: "Bid response should log consistently for each activity about skips" + def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure + def fetchBidsLogs = findProcessingRule(infrastructure, FETCH_BIDS).ruleConfiguration.and + def transmitUfpdLogs = findProcessingRule(infrastructure, TRANSMIT_UFPD).ruleConfiguration.and + def transmitEidsLogs = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and + def transmitPreciseGeoLogs = findProcessingRule(infrastructure, TRANSMIT_PRECISE_GEO).ruleConfiguration.and + def transmitTidLogs = findProcessingRule(infrastructure, TRANSMIT_TID).ruleConfiguration.and + verifyAll ([fetchBidsLogs, transmitUfpdLogs, transmitEidsLogs, transmitPreciseGeoLogs, transmitTidLogs]) { + it.privacyModule.toSet().size() == 1 + it.skipped.toSet().size() == 1 + it.result.toSet().size() == 1 + } + } + + def "PBS auction shouldn't emit errors or warnings when skip rate is out of borders"() { + given: "Default bid request" + def accountId = PBSUtils.randomNumber as String + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.trace = VERBOSE + device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) + regs.ext = new RegsExt(gpc: PBSUtils.randomString) + regs.gppSid = [US_CA_V1.intValue] + regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() + setAccountId(accountId) + } + + and: "Set up activities" + def gpc = PBSUtils.randomString + def condition = Condition.baseCondition.tap { + it.gpc = gpc + it.geo = [CAN.withState(ARIZONA)] + } + def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { + it.privacyRegulation = [IAB_US_GENERAL] + } + def activity = Activity.getDefaultActivity([activityRule]) + def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + + and: "Account gpp configuration" + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) + + and: "Save account with allow activities setup" + def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) + accountDao.save(account) + + when: "PBS processes auction requests" + def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) + + then: "Response should not contain error" + assert !bidResponse.ext?.errors + assert !bidResponse.ext?.warnings + + where: + skipRate << [Integer.MIN_VALUE, Integer.MAX_VALUE] + } + + private static List getActivityByName(List activityInfrastructures, + ActivityType activity) { def firstIndex = activityInfrastructures.findLastIndexOf { it -> it.activity == activity } def lastIndex = activityInfrastructures.findIndexOf { it -> it.activity == activity } activityInfrastructures[new IntRange(true, firstIndex, lastIndex)] } + + private static ActivityInfrastructure findProcessingRule(List infrastructures, ActivityType activity) { + def matchingActivities = getActivityByName(infrastructures, activity) + .findAll { PROCESSING_ACTIVITY_TRACE.contains(it.description) } + + if (matchingActivities.size() != 1) { + throw new IllegalStateException("Expected a single processing activity, but found ${matchingActivities.size()}") + } + + matchingActivities.first() + } } From 517ca949f620cc863a65db3467f7ba1acb7c5c3a Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Thu, 6 Feb 2025 00:29:47 +0200 Subject: [PATCH 2/3] update after review --- .../auction/ActivityInfrastructure.groovy | 2 +- .../model/response/auction/And.groovy | 7 +- .../model/response/auction/RuleResult.groovy | 6 + .../tests/privacy/ActivityTraceLogSpec.groovy | 112 +++++++++--------- 4 files changed, 68 insertions(+), 59 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/RuleResult.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ActivityInfrastructure.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ActivityInfrastructure.groovy index 1325a65e219..0d1a3ba16ad 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ActivityInfrastructure.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ActivityInfrastructure.groovy @@ -17,7 +17,7 @@ class ActivityInfrastructure { RuleConfiguration ruleConfiguration Boolean allowByDefault Boolean allowed - String result + RuleResult result String region String country } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy index 4928d7ece87..73799db84d5 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/And.groovy @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.EqualsAndHashCode import groovy.transform.ToString +import org.prebid.server.functional.model.request.auction.PrivacyModule @ToString(includeNames = true, ignoreNulls = true) @EqualsAndHashCode @@ -11,7 +12,7 @@ import groovy.transform.ToString class And { List and - String privacyModule - String skipped - String result + PrivacyModule privacyModule + Boolean skipped + RuleResult result } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/RuleResult.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/RuleResult.groovy new file mode 100644 index 00000000000..62b4256bb66 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/RuleResult.groovy @@ -0,0 +1,6 @@ +package org.prebid.server.functional.model.response.auction + +enum RuleResult { + + ALLOW, DISALLOW, ABSTAIN +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy index ae5983048f3..952149bcdbc 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy @@ -23,15 +23,21 @@ import static org.prebid.server.functional.model.pricefloors.Country.CAN import static org.prebid.server.functional.model.pricefloors.Country.USA import static org.prebid.server.functional.model.request.GppSectionId.US_CA_V1 import static org.prebid.server.functional.model.request.GppSectionId.US_CO_V1 +import static org.prebid.server.functional.model.request.GppSectionId.US_NAT_V1 import static org.prebid.server.functional.model.request.auction.ActivityType.FETCH_BIDS import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_EIDS import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_PRECISE_GEO import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_TID import static org.prebid.server.functional.model.request.auction.ActivityType.TRANSMIT_UFPD import static org.prebid.server.functional.model.request.auction.Condition.ConditionType.BIDDER +import static org.prebid.server.functional.model.request.auction.PrivacyModule.ALL +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.BASIC import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE +import static org.prebid.server.functional.model.response.auction.RuleResult.ABSTAIN +import static org.prebid.server.functional.model.response.auction.RuleResult.ALLOW +import static org.prebid.server.functional.model.response.auction.RuleResult.DISALLOW import static org.prebid.server.functional.util.privacy.model.State.ALABAMA import static org.prebid.server.functional.util.privacy.model.State.ARIZONA @@ -101,7 +107,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { country: USA.ISOAlpha3)) assert fetchBidsActivity.ruleConfiguration.every { it == null } assert fetchBidsActivity.allowByDefault.contains(activity.defaultAction) - assert fetchBidsActivity.result.contains("DISALLOW") + assert fetchBidsActivity.result.contains(DISALLOW) assert fetchBidsActivity.country.every { it == null } assert fetchBidsActivity.region.every { it == null } } @@ -141,7 +147,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { country: USA.ISOAlpha3)) assert fetchBidsActivity.allowByDefault.contains(activity.defaultAction) assert fetchBidsActivity.ruleConfiguration.every { it == null } - assert fetchBidsActivity.result.contains("ALLOW") + assert fetchBidsActivity.result.contains(ALLOW) assert fetchBidsActivity.country.every { it == null } assert fetchBidsActivity.region.every { it == null } @@ -241,7 +247,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { gpc: gpc, geoCodes: [new GeoCode(country: CAN, region: ARIZONA.abbreviation)])) assert fetchBidsActivity.allowByDefault.contains(activity.defaultAction) - assert fetchBidsActivity.result.contains("ABSTAIN") + assert fetchBidsActivity.result.contains(ABSTAIN) assert fetchBidsActivity.country.every { it == null } assert fetchBidsActivity.region.every { it == null } @@ -347,7 +353,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { assert fetchBidsActivity.ruleConfiguration.contains(new RuleConfiguration( and: [new And(and: ["USNatDefault. Precomputed result: ABSTAIN."])])) assert fetchBidsActivity.allowByDefault.contains(activity.defaultAction) - assert fetchBidsActivity.result.contains("ABSTAIN") + assert fetchBidsActivity.result.contains(ABSTAIN) assert fetchBidsActivity.country.every { it == null } assert fetchBidsActivity.region.every { it == null } @@ -405,26 +411,21 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { def "PBS auction should log info about activity in response when ext.prebid.trace=verbose and skipRate=#skipRate"() { given: "Default bid request" def accountId = PBSUtils.randomNumber as String - def bidRequest = BidRequest.defaultBidRequest.tap { + def bidRequest = getBidRequestWithPersonalData(accountId).tap { ext.prebid.trace = VERBOSE - device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) - regs.ext = new RegsExt(gpc: PBSUtils.randomString) - regs.gppSid = [US_CA_V1.intValue] - regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() - setAccountId(accountId) + regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC + regs.gppSid = [US_NAT_V1.intValue] } and: "Set up activities" - def gpc = PBSUtils.randomString def condition = Condition.baseCondition.tap { - it.gpc = gpc - it.geo = [CAN.withState(ARIZONA)] + it.gppSid = [US_NAT_V1.intValue] } def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { it.privacyRegulation = [IAB_US_GENERAL] } def activity = Activity.getDefaultActivity([activityRule]) - def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity) and: "Account gpp configuration" def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) @@ -436,11 +437,19 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { when: "PBS processes auction requests" def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) - then: "Bid response should contain verbose info in debug" + then: "Generic bidder request should have empty EIDS fields" + def genericBidderRequest = bidder.getBidderRequest(bidRequest.id) + + verifyAll { + !genericBidderRequest.user.eids + !genericBidderRequest.user?.ext?.eids + } + + and: "Bid response should contain verbose info in debug" def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure - def ruleConfigurations = findProcessingRule(infrastructure, FETCH_BIDS).ruleConfiguration.and + def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and assert ruleConfigurations.size() == 1 - assert ruleConfigurations.first.and.every { it != null } + assert ruleConfigurations.first.and.every { it.contains(DISALLOW.toString()) } and: "Should not contain information that module was skipped" verifyAll(ruleConfigurations.first) { @@ -456,29 +465,24 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { def "PBS auction should log info about module skip in response when ext.prebid.trace=verbose and skipRate is max"() { given: "Default bid request" def accountId = PBSUtils.randomNumber as String - def bidRequest = BidRequest.defaultBidRequest.tap { + def bidRequest = getBidRequestWithPersonalData(accountId).tap { ext.prebid.trace = VERBOSE - device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) - regs.ext = new RegsExt(gpc: PBSUtils.randomString) - regs.gppSid = [US_CA_V1.intValue] - regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() - setAccountId(accountId) + regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC + regs.gppSid = [US_NAT_V1.intValue] } and: "Set up activities" - def gpc = PBSUtils.randomString def condition = Condition.baseCondition.tap { - it.gpc = gpc - it.geo = [CAN.withState(ARIZONA)] + it.gppSid = [US_NAT_V1.intValue] } def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { - it.privacyRegulation = [IAB_US_GENERAL] + it.privacyRegulation = [ALL] } - def activity = Activity.getDefaultActivity([activityRule], defaultAction) - def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + def activity = Activity.getDefaultActivity([activityRule]) + def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity) and: "Account gpp configuration" - def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: MAX_PERCENT_AB) + def accountGppConfig = new AccountGppConfig(code: code, enabled: true, skipRate: MAX_PERCENT_AB) and: "Save account with allow activities setup" def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) @@ -487,40 +491,43 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { when: "PBS processes auction requests" def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) - then: "Bid response should not contain verbose info in debug" + then: "Generic bidder request should have data in EIDS fields" + def genericBidderRequest = bidder.getBidderRequest(bidRequest.id) + assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source + + and: "Bid response should not contain verbose info in debug" def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure - def ruleConfigurations = findProcessingRule(infrastructure, FETCH_BIDS).ruleConfiguration.and + def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and assert ruleConfigurations.size() == 1 assert ruleConfigurations.first.and.every { it == null } and: "Should contain information that module was skipped" verifyAll(ruleConfigurations.first) { - it.privacyModule == 'iab.usgeneral' - it.skipped == 'true' - it.result == 'ABSTAIN' + it.privacyModule == code + it.skipped == true + it.result == ABSTAIN } where: - defaultAction << [false, true] + code | defaultAction + IAB_US_GENERAL | false + IAB_US_GENERAL | true + IAB_US_CUSTOM_LOGIC | false + IAB_US_CUSTOM_LOGIC | true } def "PBS auction should log consistently for each activity about skips modules in response"() { given: "Default bid request" def accountId = PBSUtils.randomNumber as String - def bidRequest = BidRequest.defaultBidRequest.tap { + def bidRequest = getBidRequestWithPersonalData(accountId).tap { ext.prebid.trace = VERBOSE - device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) - regs.ext = new RegsExt(gpc: PBSUtils.randomString) - regs.gppSid = [US_CA_V1.intValue] - regs.gpp = new UsNatV1Consent.Builder().build() - setAccountId(accountId) + regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC + regs.gppSid = [US_NAT_V1.intValue] } and: "Set up activities" - def gpc = PBSUtils.randomString def condition = Condition.baseCondition.tap { - it.gpc = gpc - it.geo = [CAN.withState(ARIZONA)] + it.gppSid = [US_NAT_V1.intValue] } def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { it.privacyRegulation = [IAB_US_GENERAL] @@ -565,26 +572,21 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { def "PBS auction shouldn't emit errors or warnings when skip rate is out of borders"() { given: "Default bid request" def accountId = PBSUtils.randomNumber as String - def bidRequest = BidRequest.defaultBidRequest.tap { + def bidRequest = getBidRequestWithPersonalData(accountId).tap { ext.prebid.trace = VERBOSE - device = new Device(geo: new Geo(country: USA, region: ALABAMA.abbreviation)) - regs.ext = new RegsExt(gpc: PBSUtils.randomString) - regs.gppSid = [US_CA_V1.intValue] - regs.gpp = new UsNatV1Consent.Builder().setGpc(true).build() - setAccountId(accountId) + regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC + regs.gppSid = [US_NAT_V1.intValue] } and: "Set up activities" - def gpc = PBSUtils.randomString def condition = Condition.baseCondition.tap { - it.gpc = gpc - it.geo = [CAN.withState(ARIZONA)] + it.gppSid = [US_NAT_V1.intValue] } def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { it.privacyRegulation = [IAB_US_GENERAL] } def activity = Activity.getDefaultActivity([activityRule]) - def activities = AllowActivities.getDefaultAllowActivities(FETCH_BIDS, activity) + def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity) and: "Account gpp configuration" def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) From 6b91cd7be75fbd0ffae9cd8a81ab9703600726ac Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Thu, 6 Feb 2025 11:09:02 +0200 Subject: [PATCH 3/3] update after review --- .../tests/privacy/ActivityTraceLogSpec.groovy | 93 ++++++++++++++++--- 1 file changed, 81 insertions(+), 12 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy index 952149bcdbc..e42fa3fb594 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy @@ -445,7 +445,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { !genericBidderRequest.user?.ext?.eids } - and: "Bid response should contain verbose info in debug" + and: "Bid response should contain info about triggered activity in debug" def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and assert ruleConfigurations.size() == 1 @@ -495,7 +495,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { def genericBidderRequest = bidder.getBidderRequest(bidRequest.id) assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source - and: "Bid response should not contain verbose info in debug" + and: "Bid response should not contain info about triggered activity in debug" def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and assert ruleConfigurations.size() == 1 @@ -569,8 +569,8 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { } } - def "PBS auction shouldn't emit errors or warnings when skip rate is out of borders"() { - given: "Default bid request" + def "PBS auction shouldn't emit errors or warnings when skip rate is at minimum boundary"() { + given: "A bid request with verbose tracing and GPC disallow logic" def accountId = PBSUtils.randomNumber as String def bidRequest = getBidRequestWithPersonalData(accountId).tap { ext.prebid.trace = VERBOSE @@ -578,7 +578,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { regs.gppSid = [US_NAT_V1.intValue] } - and: "Set up activities" + and: "An activity rule with GPP SID and privacy regulation setup" def condition = Condition.baseCondition.tap { it.gppSid = [US_NAT_V1.intValue] } @@ -588,22 +588,91 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec { def activity = Activity.getDefaultActivity([activityRule]) def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity) - and: "Account gpp configuration" - def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: skipRate) + and: "Account GPP configuration with minimum skip rate" + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: Integer.MIN_VALUE) - and: "Save account with allow activities setup" + and: "Save the account with configured activities and privacy module" def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) accountDao.save(account) - when: "PBS processes auction requests" + when: "PBS processes the auction request" def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) - then: "Response should not contain error" + then: "Response should not contain errors or warnings" assert !bidResponse.ext?.errors assert !bidResponse.ext?.warnings - where: - skipRate << [Integer.MIN_VALUE, Integer.MAX_VALUE] + and: "Bid response should contain info about triggered activity in debug" + def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure + def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and + assert ruleConfigurations.size() == 1 + assert ruleConfigurations.first.and.every { it.contains(DISALLOW.toString()) } + + and: "Should not contain information that module was skipped" + verifyAll(ruleConfigurations.first) { + !it.privacyModule + !it.skipped + !it.result + } + + and: "Generic bidder request should have empty EIDS fields" + def genericBidderRequest = bidder.getBidderRequest(bidRequest.id) + + verifyAll { + !genericBidderRequest.user.eids + !genericBidderRequest.user?.ext?.eids + } + } + + def "PBS auction shouldn't emit errors or warnings when skip rate is at maximum boundary"() { + given: "A bid request with verbose tracing and GPC disallow logic" + def accountId = PBSUtils.randomNumber as String + def bidRequest = getBidRequestWithPersonalData(accountId).tap { + ext.prebid.trace = VERBOSE + regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC + regs.gppSid = [US_NAT_V1.intValue] + } + + and: "An activity rule with GPP SID and privacy regulation setup" + def condition = Condition.baseCondition.tap { + it.gppSid = [US_NAT_V1.intValue] + } + def activityRule = ActivityRule.getDefaultActivityRule(condition).tap { + it.privacyRegulation = [IAB_US_GENERAL] + } + def activity = Activity.getDefaultActivity([activityRule]) + def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity) + + and: "Account GPP configuration with maximum skip rate" + def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: Integer.MAX_VALUE) + + and: "Save the account with configured activities and privacy module" + def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig]) + accountDao.save(account) + + when: "PBS processes the auction request" + def bidResponse = activityPbsService.sendAuctionRequest(bidRequest) + + then: "Response should not contain errors or warnings" + assert !bidResponse.ext?.errors + assert !bidResponse.ext?.warnings + + and: "Bid response should not contain info about triggered activity in debug" + def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure + def ruleConfigurations = findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration.and + assert ruleConfigurations.size() == 1 + assert ruleConfigurations.first.and.every { it == null } + + and: "Should contain information that module was skipped" + verifyAll(ruleConfigurations.first) { + it.privacyModule == IAB_US_GENERAL + it.skipped == true + it.result == ABSTAIN + } + + and: "Generic bidder request should have data in EIDS fields" + def genericBidderRequest = bidder.getBidderRequest(bidRequest.id) + assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source } private static List getActivityByName(List activityInfrastructures,