diff --git a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy index 53f633b710c..1e33542e564 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy @@ -12,10 +12,16 @@ import spock.lang.Shared import java.time.Clock import java.time.ZonedDateTime +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS +import static org.prebid.server.functional.model.bidder.BidderName.EMPTY import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.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.request.setuid.UidWithExpiry.defaultUidWithExpiry import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.REDIRECT import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer @@ -37,11 +43,13 @@ class SetUidSpec extends BaseSpec { "adapters.${APPNEXUS.value}.usersync.cookie-family-name" : APPNEXUS.value, "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL, "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.support-cors": CORS_SUPPORT.toString()] + private static final Map GENERIC_ALIAS_CONFIG = ["adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] private static final String TCF_ERROR_MESSAGE = "The gdpr_consent param prevents cookies from being saved" private static final int UNAVAILABLE_FOR_LEGAL_REASONS_CODE = 451 @Shared - PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG) + PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + GENERIC_ALIAS_CONFIG) def "PBS should set uids cookie"() { given: "Default SetuidRequest" @@ -77,8 +85,8 @@ class SetUidSpec extends BaseSpec { def "PBS setuid should return requested uids cookie when priority bidder not present in config"() { given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": null]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": null] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Setuid request" def request = SetuidRequest.defaultSetuidRequest.tap { @@ -94,13 +102,16 @@ class SetUidSpec extends BaseSpec { then: "Response should contain requested uids" assert response.uidsCookie.tempUIDs[GENERIC] assert response.uidsCookie.tempUIDs[RUBICON] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should return prioritized uids bidder when size is full"() { given: "PBS config" def genericBidder = GENERIC - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": genericBidder.value]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": genericBidder.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Setuid request" def request = SetuidRequest.defaultSetuidRequest.tap { @@ -119,12 +130,15 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[rubiconBidder] assert response.uidsCookie.tempUIDs[genericBidder] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should remove earliest expiration bidder when size is full"() { given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": GENERIC.value]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": GENERIC.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Setuid request" def request = SetuidRequest.defaultSetuidRequest.tap { @@ -147,12 +161,15 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[APPNEXUS] assert response.uidsCookie.tempUIDs[GENERIC] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should ignore requested bidder and log metric when cookie's filled and requested bidder not in prioritize list"() { given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": APPNEXUS.value]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": APPNEXUS.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Setuid request" def bidderName = GENERIC @@ -176,14 +193,17 @@ class SetUidSpec extends BaseSpec { and: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[APPNEXUS] assert response.uidsCookie.tempUIDs[RUBICON] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should reject bidder when cookie's filled and requested bidder in pri and rejected by tcf"() { given: "Setuid request" def bidderName = RUBICON - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG - + ["gdpr.host-vendor-id": RUBICON_VENDOR_ID.toString(), - "cookie-sync.pri" : bidderName.value]) + def pbsConfig = PBS_CONFIG + ["gdpr.host-vendor-id": RUBICON_VENDOR_ID.toString(), + "cookie-sync.pri" : bidderName.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) def request = SetuidRequest.defaultSetuidRequest.tap { it.bidder = bidderName @@ -207,12 +227,15 @@ class SetUidSpec extends BaseSpec { and: "usersync.FAMILY.tcf.blocked metric should be updated" def metric = prebidServerService.sendCollectedMetricsRequest() assert metric["usersync.${bidderName.value}.tcf.blocked"] == 1 + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should remove oldest uid and log metric when cookie's filled and oldest uid's not on the pri"() { given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": GENERIC.value]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": GENERIC.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Flush metrics" flushMetrics(prebidServerService) @@ -241,12 +264,15 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[APPNEXUS] assert response.uidsCookie.tempUIDs[GENERIC] + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) } def "PBS SetUid should remove oldest bidder from uids cookie in favor of prioritized bidder"() { given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + - ["cookie-sync.pri": "$OPENX.value, $GENERIC.value" as String]) + def pbsConfig = PBS_CONFIG + ["cookie-sync.pri": "$OPENX.value, $GENERIC.value" as String] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Set uid request" def request = SetuidRequest.defaultSetuidRequest.tap { @@ -281,5 +307,26 @@ class SetUidSpec extends BaseSpec { and: "usersync.FAMILY.sets metric should be updated" assert metricsRequest["usersync.${OPENX.value}.sets"] == 1 + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS setuid should reject request when requested bidder mismatching with cookie-family-name"() { + given: "Default SetuidRequest" + def request = SetuidRequest.getDefaultSetuidRequest().tap { + it.bidder = bidderName + } + + when: "PBS processes setuid request" + prebidServerService.sendSetUidRequest(request, UidsCookie.defaultUidsCookie) + + then: "Request should fail with error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == 400 + assert exception.responseBody == 'Invalid request format: "bidder" query param is invalid' + + where: + bidderName << [UNKNOWN, WILDCARD, GENERIC_CAMEL_CASE, ALIAS, ALIAS_CAMEL_CASE] } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprSetUidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprSetUidSpec.groovy index 0fede80a71a..ce8d308c3a2 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprSetUidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GdprSetUidSpec.groovy @@ -17,6 +17,7 @@ import org.prebid.server.util.ResourceUtil 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.GENER_X import static org.prebid.server.functional.model.config.Purpose.P1 import static org.prebid.server.functional.model.config.PurposeEnforcement.FULL import static org.prebid.server.functional.model.config.PurposeEnforcement.NO @@ -53,7 +54,7 @@ class GdprSetUidSpec extends PrivacyBaseSpec { .build() } - and: "Default uids cookie with rubicon bidder" + and: "Default uids cookie with gener_x bidder" def uidsCookie = UidsCookie.defaultUidsCookie.tap { it.tempUIDs = [(GENERIC): defaultUidWithExpiry] } @@ -75,6 +76,90 @@ class GdprSetUidSpec extends PrivacyBaseSpec { ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png") } + def "PBS setuid shouldn't failed with tcf when bidder name and cookie-family-name mismatching"() { + given: "PBS with different cookie-family-name" + def pbsConfig = VENDOR_GENERIC_PBS_CONFIG + + ["adapters.${GENERIC.value}.usersync.cookie-family-name": GENER_X.value] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) + + and: "Setuid request with account" + def setuidRequest = SetuidRequest.defaultSetuidRequest.tap { + it.account = PBSUtils.randomNumber.toString() + it.uid = UUID.randomUUID().toString() + it.bidder = GENER_X + it.gdpr = "1" + it.gdprConsent = new TcfConsent.Builder() + .setPurposesLITransparency(DEVICE_ACCESS) + .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) + .build() + } + + and: "Default uids cookie with gener_x bidder" + def uidsCookie = UidsCookie.defaultUidsCookie.tap { + it.tempUIDs = [(GENER_X): defaultUidWithExpiry] + } + + and: "Save account config with purpose into DB" + def accountConfig = new AccountConfig( + auction: new AccountAuctionConfig(debugAllow: true), + privacy: new AccountPrivacyConfig(gdpr: new AccountGdprConfig(purposes: [(P1): new PurposeConfig(enforcePurpose: NO)], enabled: true))) + def account = new Account(status: ACTIVE, uuid: setuidRequest.account, config: accountConfig) + accountDao.save(account) + + when: "PBS processes setuid request" + def response = prebidServerService.sendSetUidRequest(setuidRequest, uidsCookie) + + then: "Response should contain tempUids cookie and headers" + assert response.headers.size() == 7 + assert response.uidsCookie.tempUIDs[GENER_X].uid == setuidRequest.uid + assert response.responseBody == + ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png") + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS setuid should failed with tcf when dgpr value is invalid"() { + given: "Default setuid request with account" + def setuidRequest = SetuidRequest.defaultSetuidRequest.tap { + it.account = PBSUtils.randomNumber.toString() + it.uid = UUID.randomUUID().toString() + it.bidder = GENERIC + it.gdpr = "1" + it.gdprConsent = new TcfConsent.Builder() + .setPurposesLITransparency(DEVICE_ACCESS) + .setVendorLegitimateInterest([PBSUtils.getRandomNumberWithExclusion(GENERIC_VENDOR_ID, 0, 65534)]) + .build() + } + + and: "Flush metrics" + flushMetrics(prebidServerService) + + and: "Default uids cookie with generic bidder" + def uidsCookie = UidsCookie.defaultUidsCookie.tap { + it.tempUIDs = [(GENERIC): defaultUidWithExpiry] + } + + and: "Save account config with purpose into DB" + def accountConfig = new AccountConfig( + auction: new AccountAuctionConfig(debugAllow: true), + privacy: new AccountPrivacyConfig(gdpr: new AccountGdprConfig(purposes: [(P1): new PurposeConfig(enforcePurpose: NO)], enabled: true))) + def account = new Account(status: ACTIVE, uuid: setuidRequest.account, config: accountConfig) + accountDao.save(account) + + when: "PBS processes setuid request" + prebidServerService.sendSetUidRequest(setuidRequest, uidsCookie) + + then: "Request should fail with error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == UNAVAILABLE_FOR_LEGAL_REASONS_CODE + assert exception.responseBody == TCF_ERROR_MESSAGE + + and: "Metric should be increased usersync.FAMILY.tcf.blocked" + def metric = prebidServerService.sendCollectedMetricsRequest() + assert metric["usersync.${GENERIC.value}.tcf.blocked"] == 1 + } + def "PBS setuid should failed with tcf when purpose access device enforced for account"() { given: "Default setuid request with account" def setuidRequest = SetuidRequest.defaultSetuidRequest.tap { @@ -88,11 +173,14 @@ class GdprSetUidSpec extends PrivacyBaseSpec { .build() } - and: "Default uids cookie with rubicon bidder" + and: "Default uids cookie with generic bidder" def uidsCookie = UidsCookie.defaultUidsCookie.tap { it.tempUIDs = [(GENERIC): defaultUidWithExpiry] } + and: "Flush metrics" + flushMetrics(prebidServerService) + and: "Save account config with purpose into DB" def accountConfig = new AccountConfig( auction: new AccountAuctionConfig(debugAllow: true), @@ -130,11 +218,14 @@ class GdprSetUidSpec extends PrivacyBaseSpec { .build() } - and: "Default uids cookie with rubicon bidder" + and: "Default uids cookie with generic bidder" def uidsCookie = UidsCookie.defaultUidsCookie.tap { it.tempUIDs = [(GENERIC): defaultUidWithExpiry] } + and: "Flush metrics" + flushMetrics(prebidServerService) + and: "Save account config with purpose into DB" def accountConfig = new AccountConfig( auction: new AccountAuctionConfig(debugAllow: true), @@ -176,11 +267,14 @@ class GdprSetUidSpec extends PrivacyBaseSpec { .build() } - and: "Default uids cookie with rubicon bidder" + and: "Default uids cookie with generic bidder" def uidsCookie = UidsCookie.defaultUidsCookie.tap { it.tempUIDs = [(GENERIC): defaultUidWithExpiry] } + and: "Flush metrics" + flushMetrics(prebidServerService) + and: "Save account config with purpose into DB" def accountConfig = new AccountConfig( auction: new AccountAuctionConfig(debugAllow: true), @@ -214,7 +308,7 @@ class GdprSetUidSpec extends PrivacyBaseSpec { .build() } - and: "Default uids cookie with rubicon bidder" + and: "Default uids cookie with generic bidder" def uidsCookie = UidsCookie.defaultUidsCookie.tap { it.tempUIDs = [(GENERIC): defaultUidWithExpiry] }