From 86b98af72481edcb7106e26c34d70ed3572bb4fc Mon Sep 17 00:00:00 2001 From: antonbabak Date: Tue, 27 May 2025 10:57:41 +0200 Subject: [PATCH 1/3] Bidder Usersync Skipwhen Config --- .../org/prebid/server/bidder/Usersyncer.java | 22 ++- .../server/cookie/CookieSyncService.java | 24 ++++ .../server/cookie/model/RejectionReason.java | 3 +- ...ersyncBidderRegulationScopeProperties.java | 15 ++ .../UsersyncConfigurationProperties.java | 2 + .../config/bidder/util/UsersyncerCreator.java | 6 +- .../server/auction/ExchangeServiceTest.java | 2 +- .../server/bidder/BidderCatalogTest.java | 8 +- .../bidder/UsersyncMethodChooserTest.java | 18 +-- .../server/cookie/CookieSyncServiceTest.java | 135 +++++++++++++++++- .../server/cookie/CoopSyncProviderTest.java | 2 + .../PrioritizedCoopSyncProviderTest.java | 2 + .../server/handler/SetuidHandlerTest.java | 18 +-- .../bidder/util/UsersyncerCreatorTest.java | 2 +- 14 files changed, 225 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncBidderRegulationScopeProperties.java diff --git a/src/main/java/org/prebid/server/bidder/Usersyncer.java b/src/main/java/org/prebid/server/bidder/Usersyncer.java index e5b6cad6f6e..ebe776d2e3e 100644 --- a/src/main/java/org/prebid/server/bidder/Usersyncer.java +++ b/src/main/java/org/prebid/server/bidder/Usersyncer.java @@ -3,6 +3,8 @@ import lombok.Value; import org.prebid.server.spring.config.bidder.model.usersync.CookieFamilySource; +import java.util.List; + @Value(staticConstructor = "of") public class Usersyncer { @@ -16,7 +18,23 @@ public class Usersyncer { UsersyncMethod redirect; - public static Usersyncer of(String cookieFamilyName, UsersyncMethod iframe, UsersyncMethod redirect) { - return of(true, cookieFamilyName, CookieFamilySource.ROOT, iframe, redirect); + boolean skipWhenInGdprScope; + + List gppSidToSkip; + + public static Usersyncer of(String cookieFamilyName, + UsersyncMethod iframe, + UsersyncMethod redirect, + boolean skipWhenInGdprScope, + List gppSidToSkip) { + + return of( + true, + cookieFamilyName, + CookieFamilySource.ROOT, + iframe, + redirect, + skipWhenInGdprScope, + gppSidToSkip); } } diff --git a/src/main/java/org/prebid/server/cookie/CookieSyncService.java b/src/main/java/org/prebid/server/cookie/CookieSyncService.java index fb15b5478d9..4ebd38c45ed 100644 --- a/src/main/java/org/prebid/server/cookie/CookieSyncService.java +++ b/src/main/java/org/prebid/server/cookie/CookieSyncService.java @@ -111,6 +111,8 @@ public Future processContext(CookieSyncContext cookieSyncCont .map(this::filterDisabledBidders) .map(this::filterBiddersWithoutUsersync) .map(this::filterBiddersWithDisabledUsersync) + .map(this::filterBiddersByGdpr) + .map(this::filterBiddersByGppSid) .map(this::applyRequestFilterSettings) .compose(this::applyPrivacyFilteringRules) .map(this::filterInSyncBidders); @@ -202,6 +204,26 @@ private CookieSyncContext filterBiddersWithDisabledUsersync(CookieSyncContext co RejectionReason.DISABLED_USERSYNC); } + private CookieSyncContext filterBiddersByGdpr(CookieSyncContext cookieSyncContext) { + return filterBidders( + cookieSyncContext, + bidder -> cookieSyncContext.getPrivacyContext().getTcfContext().isInGdprScope() + && bidderCatalog.usersyncerByName(bidder).map(Usersyncer::isSkipWhenInGdprScope).orElse(false), + RejectionReason.REJECTED_BY_REGULATION_SCOPE); + } + + private CookieSyncContext filterBiddersByGppSid(CookieSyncContext cookieSyncContext) { + return filterBidders( + cookieSyncContext, + bidder -> bidderCatalog.usersyncerByName(bidder) + .map(Usersyncer::getGppSidToSkip) + .map(gppSid -> !Collections.disjoint( + gppSid, + cookieSyncContext.getCookieSyncRequest().getGppSid())) + .orElse(false), + RejectionReason.REJECTED_BY_REGULATION_SCOPE); + } + /** * should be called after applying request filter, as it will populate usersync data */ @@ -469,6 +491,8 @@ private BidderUsersyncStatus rejectionStatus(String bidder, RejectionReason reas case DISABLED_USERSYNC -> builder.conditionalError(requested || coopSync, "Sync disabled by config"); case REJECTED_BY_FILTER -> builder.conditionalError(requested || coopSync, "Rejected by request filter"); case ALREADY_IN_SYNC -> builder.conditionalError(requested, "Already in sync"); + case REJECTED_BY_REGULATION_SCOPE -> builder.conditionalError( + requested || coopSync, "Rejected by regulation scope"); }; return builder.build(); diff --git a/src/main/java/org/prebid/server/cookie/model/RejectionReason.java b/src/main/java/org/prebid/server/cookie/model/RejectionReason.java index 8c503642c29..5130a3abb93 100644 --- a/src/main/java/org/prebid/server/cookie/model/RejectionReason.java +++ b/src/main/java/org/prebid/server/cookie/model/RejectionReason.java @@ -10,5 +10,6 @@ public enum RejectionReason { UNCONFIGURED_USERSYNC, DISABLED_USERSYNC, REJECTED_BY_FILTER, - ALREADY_IN_SYNC + ALREADY_IN_SYNC, + REJECTED_BY_REGULATION_SCOPE } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncBidderRegulationScopeProperties.java b/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncBidderRegulationScopeProperties.java new file mode 100644 index 00000000000..49ab5fd74b4 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncBidderRegulationScopeProperties.java @@ -0,0 +1,15 @@ +package org.prebid.server.spring.config.bidder.model.usersync; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +public class UsersyncBidderRegulationScopeProperties { + + boolean gdpr; + + List gppSid; +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncConfigurationProperties.java b/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncConfigurationProperties.java index e67debfad6c..a93fac2f41c 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncConfigurationProperties.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/model/usersync/UsersyncConfigurationProperties.java @@ -19,4 +19,6 @@ public class UsersyncConfigurationProperties { UsersyncMethodConfigurationProperties redirect; UsersyncMethodConfigurationProperties iframe; + + UsersyncBidderRegulationScopeProperties skipwhen; } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreator.java b/src/main/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreator.java index 462bd3d3cdc..b5606c719b9 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreator.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreator.java @@ -6,6 +6,7 @@ import org.prebid.server.bidder.UsersyncUtil; import org.prebid.server.bidder.Usersyncer; import org.prebid.server.spring.config.bidder.model.usersync.CookieFamilySource; +import org.prebid.server.spring.config.bidder.model.usersync.UsersyncBidderRegulationScopeProperties; import org.prebid.server.spring.config.bidder.model.usersync.UsersyncConfigurationProperties; import org.prebid.server.spring.config.bidder.model.usersync.UsersyncMethodConfigurationProperties; import org.prebid.server.util.HttpUtil; @@ -30,13 +31,16 @@ private static Usersyncer createAndValidate(UsersyncConfigurationProperties user String externalUrl) { final String cookieFamilyName = usersync.getCookieFamilyName(); + final UsersyncBidderRegulationScopeProperties skipwhenConfig = usersync.getSkipwhen(); return Usersyncer.of( usersync.getEnabled(), cookieFamilyName, cookieFamilySource, toMethod(UsersyncMethodType.IFRAME, usersync.getIframe(), cookieFamilyName, externalUrl), - toMethod(UsersyncMethodType.REDIRECT, usersync.getRedirect(), cookieFamilyName, externalUrl)); + toMethod(UsersyncMethodType.REDIRECT, usersync.getRedirect(), cookieFamilyName, externalUrl), + skipwhenConfig != null && skipwhenConfig.isGdpr(), + skipwhenConfig == null ? null : skipwhenConfig.getGppSid()); } private static UsersyncMethod toMethod(UsersyncMethodType type, diff --git a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java index c13ca6eb56f..58d0c838a44 100644 --- a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java +++ b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java @@ -299,7 +299,7 @@ public void setUp() { given(bidderCatalog.isValidName(anyString())).willReturn(true); given(bidderCatalog.isActive(anyString())).willReturn(true); given(bidderCatalog.usersyncerByName(anyString())) - .willReturn(Optional.of(Usersyncer.of("cookieFamily", null, null))); + .willReturn(Optional.of(Usersyncer.of("cookieFamily", null, null, false, null))); given(bidderCatalog.bidderInfoByName(anyString())).willReturn(BidderInfo.create( true, null, diff --git a/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java b/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java index 347279cd3b5..96861372cd3 100644 --- a/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java +++ b/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java @@ -218,7 +218,7 @@ public void metaInfoByNameShouldReturnNullForUnknownBidder() { @Test public void usersyncerByNameShouldReturnUsersyncerForKnownBidderIgnoringCase() { // given - final Usersyncer usersyncer = Usersyncer.of("name", null, null); + final Usersyncer usersyncer = Usersyncer.of("name", null, null, false, null); final BidderDeps bidderDeps = BidderDeps.of(singletonList(BidderInstanceDeps.builder() .name("BIDder") .deprecatedNames(emptyList()) @@ -233,7 +233,7 @@ public void usersyncerByNameShouldReturnUsersyncerForKnownBidderIgnoringCase() { @Test public void cookieFamilyNameShouldReturnCookieFamilyForKnownBidderIgnoringCase() { // given - final Usersyncer usersyncer = Usersyncer.of("name", null, null); + final Usersyncer usersyncer = Usersyncer.of("name", null, null, false, null); final BidderDeps bidderDeps = BidderDeps.of(singletonList(BidderInstanceDeps.builder() .name("BIDder") .deprecatedNames(emptyList()) @@ -310,7 +310,7 @@ public void usersyncReadyBiddersShouldReturnBiddersThatCanSync() { .name("bidder-with-usersync") .deprecatedNames(emptyList()) .bidderInfo(infoOfBidderWithUsersyncConfig) - .usersyncer(Usersyncer.of("bidder-with-usersync-family", null, null)) + .usersyncer(Usersyncer.of("bidder-with-usersync-family", null, null, false, null)) .build())), BidderDeps.of(singletonList(BidderInstanceDeps.builder() .name("bidder-without-usersync") @@ -320,7 +320,7 @@ public void usersyncReadyBiddersShouldReturnBiddersThatCanSync() { BidderDeps.of(singletonList(BidderInstanceDeps.builder() .name("disabled-bidder-with-usersync") .bidderInfo(infoOfDisabledBidderWithUsersyncConfig) - .usersyncer(Usersyncer.of("isabled-bidder-with-usersync-family", null, null)) + .usersyncer(Usersyncer.of("isabled-bidder-with-usersync-family", null, null, false, null)) .deprecatedNames(emptyList()) .build()))); diff --git a/src/test/java/org/prebid/server/bidder/UsersyncMethodChooserTest.java b/src/test/java/org/prebid/server/bidder/UsersyncMethodChooserTest.java index c191159e71d..b129a075dce 100644 --- a/src/test/java/org/prebid/server/bidder/UsersyncMethodChooserTest.java +++ b/src/test/java/org/prebid/server/bidder/UsersyncMethodChooserTest.java @@ -58,7 +58,7 @@ public void shouldReturnRedirectMethodWhenIframeMethodFilterExcludeAndNullBidder null, CookieSyncRequest.FilterType.exclude), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -93,7 +93,7 @@ public void shouldReturnSecondaryMethodWhenInMethodFilterExcludeList() { mapper.createArrayNode().add(BIDDER), CookieSyncRequest.FilterType.exclude), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -111,7 +111,7 @@ public void shouldReturnSecondaryMethodWhenMethodFilterExcludesAll() { new TextNode("*"), CookieSyncRequest.FilterType.exclude), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -180,7 +180,7 @@ public void shouldReturnSecondaryMethodWhenNotInMethodFilterIncludeList() { mapper.createArrayNode().add("anotherbidder"), CookieSyncRequest.FilterType.include), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -231,7 +231,7 @@ public void shouldReturnSecondaryMethodWhenMethodFilterIncludeListIsNotArray() { new IntNode(1), CookieSyncRequest.FilterType.include), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter).choose(usersyncer, BIDDER); @@ -248,7 +248,7 @@ public void shouldReturnSecondaryMethodWhenMethodFilterIncludeListIsNotStringArr mapper.createArrayNode().add(1), CookieSyncRequest.FilterType.include), null); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -268,7 +268,7 @@ public void shouldReturnSecondaryMethodWhenPrimaryIsFilteredOutAndSecondIsNot() CookieSyncRequest.MethodFilter.of( new TextNode("*"), CookieSyncRequest.FilterType.include)); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -288,7 +288,7 @@ public void shouldReturnNullWhenPrimaryAndSecondaryAreFilteredOut() { CookieSyncRequest.MethodFilter.of( new TextNode("*"), CookieSyncRequest.FilterType.exclude)); - final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url")); + final Usersyncer usersyncer = Usersyncer.of(null, iframeMethod("url"), redirectMethod("url"), false, null); // when final UsersyncMethod chosenMethod = UsersyncMethodChooser.from(filter) @@ -329,7 +329,7 @@ public void shouldReturnNullWhenPrimaryIsFilteredOutAndNoSecondary() { } private Usersyncer iframeUsersyncer(String url) { - return Usersyncer.of(null, iframeMethod(url), null); + return Usersyncer.of(null, iframeMethod(url), null, false, null); } private UsersyncMethod iframeMethod(String url) { diff --git a/src/test/java/org/prebid/server/cookie/CookieSyncServiceTest.java b/src/test/java/org/prebid/server/cookie/CookieSyncServiceTest.java index 2bb02ee4463..bafc6a11d16 100644 --- a/src/test/java/org/prebid/server/cookie/CookieSyncServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/CookieSyncServiceTest.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -404,7 +405,9 @@ public void processContextShouldRejectBiddersWithDisabledUsersync() { false, "bidder-with-disabled-usersync", "bidder-with-disabled-usersync-cookie-family", - CookieFamilySource.ROOT); + CookieFamilySource.ROOT, + false, + null); givenAllAllowedTcfResultForBidders("requested-bidder", "coop-sync-bidder", "bidder-with-disabled-usersync"); @@ -422,6 +425,124 @@ public void processContextShouldRejectBiddersWithDisabledUsersync() { .isEqualTo(Map.of("bidder-with-disabled-usersync", RejectionReason.DISABLED_USERSYNC)); } + @Test + public void processContextShouldRejectBiddersWhenUserIsGdprScope() { + // given + givenCoopSyncBidders("coop-sync-bidder"); + + givenValidActiveBidders("requested-bidder", "coop-sync-bidder", "bidder-skipwhen-in-gdpr-scope"); + givenUsersyncersForBidders("requested-bidder", "coop-sync-bidder"); + givenUsersyncerForBidder( + true, + "bidder-skipwhen-in-gdpr-scope", + "bidder-skipwhen-in-gdpr-scope-cookie-family", + CookieFamilySource.ROOT, + true, + null); + + givenAllAllowedTcfResultForBidders("requested-bidder", "coop-sync-bidder", "bidder-skipwhen-in-gdpr-scope"); + + final TcfContext givenTcfContext = TcfContext.builder() + .inGdprScope(true) + .consentValid(true) + .consentString("consent-string") + .build(); + + final CookieSyncContext cookieSyncContext = givenCookieSyncContext(builder -> builder + .privacyContext(givenPrivacyContext(givenTcfContext)) + .cookieSyncRequest(givenCookieSyncRequest("requested-bidder", "bidder-skipwhen-in-gdpr-scope"))); + + // when + final Future result = target.processContext(cookieSyncContext); + + // then + assertThat(result).isSucceeded() + .unwrap() + .extracting(CookieSyncContext::getBiddersContext) + .extracting(BiddersContext::rejectedBidders) + .isEqualTo(Map.of("bidder-skipwhen-in-gdpr-scope", RejectionReason.REJECTED_BY_REGULATION_SCOPE)); + } + + @Test + public void processContextShouldRejectBiddersWhenBidderShouldBeSkippedForSid() { + // given + givenCoopSyncBidders("coop-sync-bidder"); + + givenValidActiveBidders( + "requested-bidder", + "coop-sync-bidder", + "bidder-skipwhen-sid-1", + "bidder-skipwhen-sid-2", + "bidder-skipwhen-sid-1-3", + "bidder-skipwhen-sid-absent"); + + givenUsersyncersForBidders("requested-bidder", "coop-sync-bidder"); + givenUsersyncerForBidder( + true, + "bidder-skipwhen-sid-1", + "bidder-skipwhen-sid-1-cookie-family", + CookieFamilySource.ROOT, + false, + List.of(1)); + + givenUsersyncerForBidder( + true, + "bidder-skipwhen-sid-2", + "bidder-skipwhen-sid-2-cookie-family", + CookieFamilySource.ROOT, + false, + List.of(2)); + + givenUsersyncerForBidder( + true, + "bidder-skipwhen-sid-1-3", + "bidder-skipwhen-sid-1-3-cookie-family", + CookieFamilySource.ROOT, + false, + List.of(1, 3)); + + givenUsersyncerForBidder( + true, + "bidder-skipwhen-sid-absent", + "bidder-skipwhen-sid-absent-cookie-family", + CookieFamilySource.ROOT, + false, + null); + + givenAllAllowedTcfResultForBidders( + "requested-bidder", + "coop-sync-bidder", + "bidder-skipwhen-sid-1", + "bidder-skipwhen-sid-2", + "bidder-skipwhen-sid-1-3", + "bidder-skipwhen-sid-absent"); + + final CookieSyncRequest givenCookieSyncRequest = CookieSyncRequest.builder() + .bidders(Set.of( + "requested-bidder", + "bidder-skipwhen-sid-1", + "bidder-skipwhen-sid-2", + "bidder-skipwhen-sid-1-3", + "bidder-skipwhen-sid-absent")) + .gppSid(List.of(1, 10)) + .build(); + + final CookieSyncContext cookieSyncContext = givenCookieSyncContext(builder -> builder + .cookieSyncRequest(givenCookieSyncRequest)); + + // when + final Future result = target.processContext(cookieSyncContext); + + // then + assertThat(result).isSucceeded() + .unwrap() + .extracting(CookieSyncContext::getBiddersContext) + .extracting(BiddersContext::rejectedBidders) + .isEqualTo(Map.of( + "bidder-skipwhen-sid-1", RejectionReason.REJECTED_BY_REGULATION_SCOPE, + "bidder-skipwhen-sid-1-3", RejectionReason.REJECTED_BY_REGULATION_SCOPE)); + } + @Test public void processContextShouldApplyRequestFilteringRules() { // given @@ -892,7 +1013,7 @@ public void prepareResponseShouldReturnWarningForAliasesSyncedAsRootCookieFamily given(bidderCatalog.isValidName("alias")).willReturn(true); given(bidderCatalog.isActive("alias")).willReturn(true); given(bidderCatalog.isAlias("alias")).willReturn(true); - givenUsersyncerForBidder(true, "alias", "root-cookie-family", CookieFamilySource.ROOT); + givenUsersyncerForBidder(true, "alias", "root-cookie-family", CookieFamilySource.ROOT, false, null); final CookieSyncContext cookieSyncContext = givenCookieSyncContext( cookieSyncContextBuilder -> cookieSyncContextBuilder.debug(true), @@ -920,7 +1041,7 @@ public void prepareResponseShouldNotReturnWarningForAliasesSyncedAsAliasCookieFa given(bidderCatalog.isValidName("alias")).willReturn(true); given(bidderCatalog.isActive("alias")).willReturn(true); given(bidderCatalog.isAlias("alias")).willReturn(true); - givenUsersyncerForBidder(true, "alias", "alias-cookie-family", CookieFamilySource.ALIAS); + givenUsersyncerForBidder(true, "alias", "alias-cookie-family", CookieFamilySource.ALIAS, false, null); final CookieSyncContext cookieSyncContext = givenCookieSyncContext( cookieSyncContextBuilder -> cookieSyncContextBuilder.debug(true), @@ -1128,17 +1249,19 @@ private void givenUsersyncersForBidders(String... bidders) { } private void givenUsersyncerForBidder(String bidder) { - givenUsersyncerForBidder(true, bidder, bidder + "-cookie-family", CookieFamilySource.ROOT); + givenUsersyncerForBidder(true, bidder, bidder + "-cookie-family", CookieFamilySource.ROOT, false, null); } private void givenUsersyncerForBidder(boolean enabled, String bidder, String cookieFamilyName, - CookieFamilySource cookieFamilySource) { + CookieFamilySource cookieFamilySource, + boolean gdpr, + List gppSid) { final UsersyncMethod usersyncMethod = givenUsersyncMethod(bidder); final Usersyncer usersyncer = Usersyncer.of( - enabled, cookieFamilyName, cookieFamilySource, usersyncMethod, null); + enabled, cookieFamilyName, cookieFamilySource, usersyncMethod, null, gdpr, gppSid); given(bidderCatalog.usersyncerByName(eq(bidder))).willReturn(Optional.of(usersyncer)); given(bidderCatalog.cookieFamilyName(eq(bidder))).willReturn(Optional.of(cookieFamilyName)); diff --git a/src/test/java/org/prebid/server/cookie/CoopSyncProviderTest.java b/src/test/java/org/prebid/server/cookie/CoopSyncProviderTest.java index 48d5ce91667..49ee89ff6d8 100644 --- a/src/test/java/org/prebid/server/cookie/CoopSyncProviderTest.java +++ b/src/test/java/org/prebid/server/cookie/CoopSyncProviderTest.java @@ -176,6 +176,8 @@ private void givenValidBidderWithCookieSync(String bidder) { Optional.of(Usersyncer.of( "cookie-family-name", UsersyncMethod.builder().build(), + null, + false, null))); } } diff --git a/src/test/java/org/prebid/server/cookie/PrioritizedCoopSyncProviderTest.java b/src/test/java/org/prebid/server/cookie/PrioritizedCoopSyncProviderTest.java index 4964d8ad4fa..a6e24bed906 100644 --- a/src/test/java/org/prebid/server/cookie/PrioritizedCoopSyncProviderTest.java +++ b/src/test/java/org/prebid/server/cookie/PrioritizedCoopSyncProviderTest.java @@ -106,6 +106,8 @@ private void givenValidBidderWithCookieSync(String bidder) { Optional.of(Usersyncer.of( "cookie-family-name", UsersyncMethod.builder().build(), + null, + false, null))); } } diff --git a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java index e83b75b83d2..ed88f7f6fdd 100644 --- a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java @@ -153,15 +153,15 @@ public void setUp() { given(bidderCatalog.isAlias(any())).willReturn(false); given(bidderCatalog.usersyncerByName(eq(RUBICON))).willReturn( - Optional.of(Usersyncer.of(RUBICON, null, redirectMethod()))); + Optional.of(Usersyncer.of(RUBICON, null, redirectMethod(), false, null))); given(bidderCatalog.cookieFamilyName(eq(RUBICON))).willReturn(Optional.of(RUBICON)); given(bidderCatalog.usersyncerByName(eq(FACEBOOK))).willReturn( - Optional.of(Usersyncer.of(FACEBOOK, null, redirectMethod()))); + Optional.of(Usersyncer.of(FACEBOOK, null, redirectMethod(), false, null))); given(bidderCatalog.cookieFamilyName(eq(FACEBOOK))).willReturn(Optional.of(FACEBOOK)); given(bidderCatalog.usersyncerByName(eq(APPNEXUS))).willReturn( - Optional.of(Usersyncer.of(ADNXS, null, redirectMethod()))); + Optional.of(Usersyncer.of(ADNXS, null, redirectMethod(), false, null))); given(bidderCatalog.cookieFamilyName(eq(APPNEXUS))).willReturn(Optional.of(ADNXS)); given(activityInfrastructure.isAllowed(any(), any())) @@ -532,7 +532,7 @@ public void shouldSendEmptyResponseWhenFParamIsEqualToBWhenTypeIsRedirect() { given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); given(bidderCatalog.usersyncReadyBidders()).willReturn(singleton(RUBICON)); given(bidderCatalog.usersyncerByName(any())) - .willReturn(Optional.of(Usersyncer.of(RUBICON, null, redirectMethod()))); + .willReturn(Optional.of(Usersyncer.of(RUBICON, null, redirectMethod(), false, null))); setuidHandler = new SetuidHandler( 2000, @@ -569,7 +569,7 @@ public void shouldSendEmptyResponseWhenFParamNotDefinedAndTypeIsIframe() { .willReturn(updated(uidsCookie)); given(bidderCatalog.usersyncerByName(eq(RUBICON))).willReturn( - Optional.of(Usersyncer.of(RUBICON, iframeMethod(), null))); + Optional.of(Usersyncer.of(RUBICON, iframeMethod(), null, false, null))); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); @@ -611,7 +611,7 @@ public void shouldSendPixelWhenFParamNotDefinedAndTypeIsRedirect() { given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(bidderCatalog.usersyncReadyBidders()).willReturn(singleton(RUBICON)); given(bidderCatalog.usersyncerByName(any())) - .willReturn(Optional.of(Usersyncer.of(RUBICON, null, redirectMethod()))); + .willReturn(Optional.of(Usersyncer.of(RUBICON, null, redirectMethod(), false, null))); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); setuidHandler = new SetuidHandler( @@ -844,11 +844,11 @@ public void shouldThrowExceptionInCaseOfBaseBidderCookieFamilyNameDuplicates() { .willReturn(Set.of(RUBICON, FACEBOOK, firstDuplicateName, secondDuplicateName, thirdDuplicateName)); given(bidderCatalog.isAlias(thirdDuplicateName)).willReturn(true); given(bidderCatalog.usersyncerByName(eq(firstDuplicateName))).willReturn( - Optional.of(Usersyncer.of(RUBICON, iframeMethod(), redirectMethod()))); + Optional.of(Usersyncer.of(RUBICON, iframeMethod(), redirectMethod(), false, null))); given(bidderCatalog.usersyncerByName(eq(secondDuplicateName))).willReturn( - Optional.of(Usersyncer.of(FACEBOOK, iframeMethod(), redirectMethod()))); + Optional.of(Usersyncer.of(FACEBOOK, iframeMethod(), redirectMethod(), false, null))); given(bidderCatalog.usersyncerByName(eq(thirdDuplicateName))).willReturn( - Optional.of(Usersyncer.of(FACEBOOK, iframeMethod(), redirectMethod()))); + Optional.of(Usersyncer.of(FACEBOOK, iframeMethod(), redirectMethod(), false, null))); final Executable exceptionSource = () -> new SetuidHandler( 2000, diff --git a/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java b/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java index 78ac075c285..7337d5d8b1c 100644 --- a/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java +++ b/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java @@ -117,7 +117,7 @@ public void createShouldReturnUsersyncerWithPrimaryAndSecondaryMethods() { .build(); assertThat(result).isEqualTo( - Usersyncer.of("rubicon", expectedIframeMethod, expectedRedirectMethod)); + Usersyncer.of("rubicon", expectedIframeMethod, expectedRedirectMethod, false, null)); } @Test From b51a17ede20e5b3a4bcf92e4c3435bb86b39a180 Mon Sep 17 00:00:00 2001 From: osulzhenko <125548596+osulzhenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:48:30 +0300 Subject: [PATCH 2/3] Tests: Bidder Usersync Skipwhen Config (#4028) --- .../tests/privacy/GppCookieSyncSpec.groovy | 256 +++++++++++++++++- 1 file changed, 254 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy index a462e91a1ba..40bb6e74d96 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy @@ -1,6 +1,12 @@ package org.prebid.server.functional.tests.privacy import io.netty.handler.codec.http.HttpResponseStatus +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AccountGdprConfig +import org.prebid.server.functional.model.config.AccountPrivacyConfig +import org.prebid.server.functional.model.config.PurposeConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.GppSectionId import org.prebid.server.functional.model.request.cookiesync.CookieSyncRequest import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo import org.prebid.server.functional.service.PrebidServerException @@ -13,7 +19,10 @@ import org.prebid.server.functional.util.privacy.TcfConsent import org.prebid.server.functional.util.privacy.gpp.TcfEuV2Consent import org.prebid.server.functional.util.privacy.gpp.UsV1Consent +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.config.Purpose.P1 +import static org.prebid.server.functional.model.config.PurposeEnforcement.NO import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2 import static org.prebid.server.functional.model.request.GppSectionId.USP_V1 import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.IFRAME @@ -28,15 +37,26 @@ class GppCookieSyncSpec extends BaseSpec { private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT private static final boolean CORS_SUPPORT = false private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync" + private static final GppSectionId FIRST_GPP_SECTION = PBSUtils.getRandomEnum(GppSectionId.class) + private static final GppSectionId SECOND_GPP_SECTION = PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION]) + private static final Map GENERIC_CONFIG = [ "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, "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_WITH_SKIP_CONFIG = [ + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : "$networkServiceContainer.rootUri/generic-usersync&redir={{redirect_url}}".toString(), + "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'true', + "adapters.${GENERIC.value}.usersync.skipwhen.gpp_sid" : "${FIRST_GPP_SECTION.value}, ${SECOND_GPP_SECTION.value}".toString(), + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.support-cors": CORS_SUPPORT.toString()] private static PrebidServerService prebidServerService = pbsServiceFactory.getService(GENERIC_CONFIG) + private static PrebidServerService prebidServerServiceWithSkipConfig = pbsServiceFactory.getService(GENERIC_WITH_SKIP_CONFIG + GENERIC_ALIAS_CONFIG) def cleanupSpec() { pbsServiceFactory.removeContainer(GENERIC_CONFIG) + pbsServiceFactory.removeContainer(GENERIC_WITH_SKIP_CONFIG + GENERIC_ALIAS_CONFIG) } def "PBS cookie sync request should set GDPR to 1 when gpp_sid contains 2"() { @@ -171,8 +191,8 @@ class GppCookieSyncSpec extends BaseSpec { it.gpp = new TcfEuV2Consent.Builder().build() it.gdpr = null it.gdprConsent = new TcfConsent.Builder().setPurposesLITransparency(DEVICE_ACCESS) - .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) - .build() + .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) + .build() } when: "PBS processes cookie sync request" @@ -261,4 +281,236 @@ class GppCookieSyncSpec extends BaseSpec { where: userSyncFormat << [REDIRECT, IFRAME] } + + def "PBS should emit proper error message when request contain gdpr config and global skip gdpr config for adapter"() { + given: "Default CookieSyncRequest with gdpr config" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2.intValue + it.gdpr = 1 + it.gdprConsent = new TcfConsent.Builder().build() + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url shouldn't contain cookies and userSync" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert !bidderStatus.userSync + assert !bidderStatus.noCookie + + and: "Response should contain proper error message" + assert bidderStatus.error == "Rejected by regulation scope" + } + + def "PBS should emit proper error message when alias request contain gdpr config and global skip gdpr config for adapter"() { + given: "Default CookieSyncRequest with gdpr config" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.bidders = [ALIAS] + it.gppSid = TCF_EU_V2.intValue + it.gdpr = 1 + it.gdprConsent = new TcfConsent.Builder().build() + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url shouldn't contain cookies and userSync" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert !bidderStatus.userSync + assert !bidderStatus.noCookie + + and: "Response should contain proper error message" + assert bidderStatus.error == "Rejected by regulation scope" + } + + def "PBS should emit proper error message when request contain gpp config and specific global skip gpp config for adapter"() { + given: "Default CookieSyncRequest with gpp and gppSid" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2.intValue + it.gpp = new UsV1Consent.Builder().build() + it.gppSid = gppSid + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url shouldn't contain cookies and userSync" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert !bidderStatus.userSync + assert !bidderStatus.noCookie + + and: "Response should contain proper error message" + assert bidderStatus.error == "Rejected by regulation scope" + + where: + gppSid << ["${FIRST_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}", + "${FIRST_GPP_SECTION.value}, ${SECOND_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}, ${FIRST_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}, ${FIRST_GPP_SECTION.value}", + "${PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value}, ${SECOND_GPP_SECTION.value}", + "${FIRST_GPP_SECTION.value}, ${PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value}" + ] + } + + def "PBS should emit proper error message when alias request contain gpp config and specific global skip gpp config for adapter"() { + given: "Default CookieSyncRequest with gpp and gppSid" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2.intValue + it.bidders = [ALIAS] + it.gpp = new UsV1Consent.Builder().build() + it.gppSid = gppSid + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url shouldn't contain cookies and userSync" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert !bidderStatus.userSync + assert !bidderStatus.noCookie + + and: "Response should contain proper error message" + assert bidderStatus.error == "Rejected by regulation scope" + + where: + gppSid << ["${FIRST_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}", + "${FIRST_GPP_SECTION.value}, ${SECOND_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}, ${FIRST_GPP_SECTION.value}", + "${SECOND_GPP_SECTION.value}, ${FIRST_GPP_SECTION.value}", + "${PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value}, ${SECOND_GPP_SECTION.value}", + "${FIRST_GPP_SECTION.value}, ${PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value}" + ] + } + + def "PBS shouldn't emit error message when request doesn't contain gdpr config and global skip gdpr config for adapter"() { + given: "Default CookieSyncRequest with gdpr config" + def gppSid = TCF_EU_V2 + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = gppSid.intValue + it.gdpr = 0 + it.gdprConsent = new TcfConsent.Builder().build() + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url should contain cookies and userSync" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp") == "" + assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp_sid") == gppSid.value + + and: "Response shouldn't contains any error" + assert !bidderStatus.error + } + + def "PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config disabled for adapter"() { + given: "Pbs config with usersync.#userSyncFormat.url" + def pbsConfig = [ + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL, + "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'false', + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.support-cors": CORS_SUPPORT.toString()] + def prebidServerService = pbsServiceFactory.getService(pbsConfig) + + and: "Default CookieSyncRequest with gdpr config" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2 + it.gdpr = 1 + it.gdprConsent = new TcfConsent.Builder().setPurposesLITransparency(DEVICE_ACCESS) + .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) + .build() + it.account = PBSUtils.randomNumber + } + + and: "Save account config with requireConsent into DB" + def purposes = [(P1): new PurposeConfig(enforcePurpose: NO, enforceVendors: false)] + def accountGdprConfig = new AccountGdprConfig(purposes: purposes) + def privacyConfig = new AccountPrivacyConfig(gdpr: accountGdprConfig) + def account = new Account(uuid: cookieSyncRequest.account, config: new AccountConfig(privacy: privacyConfig)) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain proper userSync url" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert bidderStatus.userSync?.url == USER_SYNC_URL + + and: "Response shouldn't contains any error" + assert !bidderStatus.error + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(pbsConfig) + } + + def "PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config default for adapter"() { + given: "Default CookieSyncRequest with gdpr config" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2 + it.gdpr = 1 + it.gdprConsent = new TcfConsent.Builder().setPurposesLITransparency(DEVICE_ACCESS) + .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) + .build() + it.account = PBSUtils.randomNumber + } + + and: "Save account config with requireConsent into DB" + def purposes = [(P1): new PurposeConfig(enforcePurpose: NO, enforceVendors: false)] + def accountGdprConfig = new AccountGdprConfig(purposes: purposes) + def privacyConfig = new AccountPrivacyConfig(gdpr: accountGdprConfig) + def account = new Account(uuid: cookieSyncRequest.account, config: new AccountConfig(privacy: privacyConfig)) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain proper userSync url" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert bidderStatus.userSync?.url == USER_SYNC_URL + + and: "Response shouldn't contains any error" + assert !bidderStatus.error + } + + def "PBS shouldn't emit error message when request doesn't contain matched gpp config and specific global skip gpp config for adapter"() { + given: "Default CookieSyncRequest with gpp and gppSid" + def gpp = new UsV1Consent.Builder().build() + def gppSid = "${PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value}" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = TCF_EU_V2.intValue + it.gpp = gpp + it.gppSid = gppSid + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response userSync url should contain gpp and gppSid" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp") == gpp.toString() + assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp_sid") == gppSid + + and: "Response shouldn't contains any error" + assert !bidderStatus.error + } + + def "PBS should also include validation warning when request matches skip config and has validation issue at same time"() { + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.gppSid = PBSUtils.getRandomNumberWithExclusion(TCF_EU_V2.intValue) + it.gdpr = 1 + it.gdprConsent = new TcfConsent.Builder().build() + } + + when: "PBS processes cookie sync request" + def response = prebidServerServiceWithSkipConfig.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain a warning" + assert response.warnings == ["GPP scope does not match TCF2 scope"] + + then: "Privacy for bidder should be enforced" + def bidderStatus = response.getBidderUserSync(GENERIC) + assert bidderStatus.error == "Rejected by regulation scope" + } } From 1b25bdc607d46a446351ceeab59c3c8e71d8f9c0 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 23 Jun 2025 14:58:32 +0300 Subject: [PATCH 3/3] Update functional test, update `it.gppSid = TCF_EU_V2.value` --- .../functional/tests/privacy/GppCookieSyncSpec.groovy | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy index 40bb6e74d96..a5a6a13ca09 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/GppCookieSyncSpec.groovy @@ -18,6 +18,7 @@ import org.prebid.server.functional.util.privacy.CcpaConsent import org.prebid.server.functional.util.privacy.TcfConsent import org.prebid.server.functional.util.privacy.gpp.TcfEuV2Consent import org.prebid.server.functional.util.privacy.gpp.UsV1Consent +import spock.lang.IgnoreRest import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC @@ -416,9 +417,10 @@ class GppCookieSyncSpec extends BaseSpec { and: "Default CookieSyncRequest with gdpr config" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - it.gppSid = TCF_EU_V2 + it.gppSid = TCF_EU_V2.value it.gdpr = 1 - it.gdprConsent = new TcfConsent.Builder().setPurposesLITransparency(DEVICE_ACCESS) + it.gdprConsent = new TcfConsent.Builder() + .setPurposesLITransparency(DEVICE_ACCESS) .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) .build() it.account = PBSUtils.randomNumber @@ -448,9 +450,10 @@ class GppCookieSyncSpec extends BaseSpec { def "PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config default for adapter"() { given: "Default CookieSyncRequest with gdpr config" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - it.gppSid = TCF_EU_V2 + it.gppSid = TCF_EU_V2.value it.gdpr = 1 - it.gdprConsent = new TcfConsent.Builder().setPurposesLITransparency(DEVICE_ACCESS) + it.gdprConsent = new TcfConsent.Builder() + .setPurposesLITransparency(DEVICE_ACCESS) .setVendorLegitimateInterest([GENERIC_VENDOR_ID]) .build() it.account = PBSUtils.randomNumber