Skip to content

Commit 31e1245

Browse files
Skipped Privacy Modules (prebid#3835)
1 parent 0944054 commit 31e1245

File tree

7 files changed

+187
-9
lines changed

7 files changed

+187
-9
lines changed

src/main/java/org/prebid/server/activity/infrastructure/ActivityInfrastructure.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import org.prebid.server.activity.ComponentType;
66
import org.prebid.server.activity.infrastructure.debug.ActivityInfrastructureDebug;
77
import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
8+
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
89
import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInfrastructure;
910

1011
import java.util.List;
1112
import java.util.Map;
1213
import java.util.Objects;
14+
import java.util.Set;
1315

1416
public class ActivityInfrastructure {
1517

@@ -48,4 +50,8 @@ public void updateActivityMetrics(Activity activity, ComponentType componentType
4850
public List<ExtTraceActivityInfrastructure> debugTrace() {
4951
return debug.trace();
5052
}
53+
54+
public Set<PrivacyModuleQualifier> skippedPrivacyModules() {
55+
return debug.skippedPrivacyModules();
56+
}
5157
}

src/main/java/org/prebid/server/activity/infrastructure/creator/rule/PrivacyModulesRuleCreator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.prebid.server.activity.infrastructure.creator.ActivityControllerCreationContext;
66
import org.prebid.server.activity.infrastructure.creator.PrivacyModuleCreationContext;
77
import org.prebid.server.activity.infrastructure.creator.privacy.PrivacyModuleCreator;
8-
import org.prebid.server.activity.infrastructure.privacy.AbstainPrivacyModule;
8+
import org.prebid.server.activity.infrastructure.privacy.SkippedPrivacyModule;
99
import org.prebid.server.activity.infrastructure.privacy.PrivacyModule;
1010
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
1111
import org.prebid.server.activity.infrastructure.rule.AndRule;
@@ -84,7 +84,7 @@ private PrivacyModule createPrivacyModule(PrivacyModuleQualifier privacyModuleQu
8484
ActivityControllerCreationContext creationContext) {
8585

8686
if (creationContext.getSkipPrivacyModules().contains(privacyModuleQualifier)) {
87-
return new AbstainPrivacyModule(privacyModuleQualifier);
87+
return new SkippedPrivacyModule(privacyModuleQualifier);
8888
}
8989

9090
return privacyModulesCreators.get(privacyModuleQualifier)

src/main/java/org/prebid/server/activity/infrastructure/debug/ActivityInfrastructureDebug.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import org.prebid.server.activity.Activity;
44
import org.prebid.server.activity.ComponentType;
55
import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
6+
import org.prebid.server.activity.infrastructure.privacy.SkippedPrivacyModule;
7+
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
8+
import org.prebid.server.activity.infrastructure.rule.AndRule;
69
import org.prebid.server.activity.infrastructure.rule.Rule;
710
import org.prebid.server.json.JacksonMapper;
811
import org.prebid.server.metric.Metrics;
@@ -15,14 +18,17 @@
1518

1619
import java.util.ArrayList;
1720
import java.util.Collections;
21+
import java.util.EnumSet;
1822
import java.util.List;
1923
import java.util.Objects;
24+
import java.util.Set;
2025

2126
public class ActivityInfrastructureDebug {
2227

2328
private final String accountId;
2429
private final TraceLevel traceLevel;
2530
private final List<ExtTraceActivityInfrastructure> traceLog;
31+
private final Set<PrivacyModuleQualifier> skippedPrivacyModules;
2632
private final Metrics metrics;
2733
private final JacksonMapper jacksonMapper;
2834

@@ -34,6 +40,7 @@ public ActivityInfrastructureDebug(String accountId,
3440
this.accountId = accountId;
3541
this.traceLevel = traceLevel;
3642
this.traceLog = new ArrayList<>();
43+
this.skippedPrivacyModules = EnumSet.noneOf(PrivacyModuleQualifier.class);
3744
this.metrics = Objects.requireNonNull(metrics);
3845
this.jacksonMapper = Objects.requireNonNull(jacksonMapper);
3946
}
@@ -56,6 +63,8 @@ public void emitActivityInvocationDefaultResult(boolean defaultResult) {
5663
}
5764

5865
public void emitProcessedRule(Rule rule, Rule.Result result) {
66+
collectSkippedPrivacyModules(rule);
67+
5968
if (atLeast(TraceLevel.basic)) {
6069
traceLog.add(ExtTraceActivityRule.of(
6170
"Processing rule.",
@@ -69,6 +78,17 @@ public void emitProcessedRule(Rule rule, Rule.Result result) {
6978
}
7079
}
7180

81+
private void collectSkippedPrivacyModules(Rule rule) {
82+
if (rule instanceof SkippedPrivacyModule module) {
83+
skippedPrivacyModules.add(module.skippedModule());
84+
} else if (rule instanceof AndRule andRule) {
85+
andRule.rules().stream()
86+
.filter(SkippedPrivacyModule.class::isInstance)
87+
.map(SkippedPrivacyModule.class::cast)
88+
.forEach(module -> skippedPrivacyModules.add(module.skippedModule()));
89+
}
90+
}
91+
7292
public void emitActivityInvocationResult(Activity activity,
7393
ActivityInvocationPayload activityInvocationPayload,
7494
boolean result) {
@@ -102,6 +122,10 @@ public List<ExtTraceActivityInfrastructure> trace() {
102122
return Collections.unmodifiableList(traceLog);
103123
}
104124

125+
public Set<PrivacyModuleQualifier> skippedPrivacyModules() {
126+
return Collections.unmodifiableSet(skippedPrivacyModules);
127+
}
128+
105129
private boolean atLeast(TraceLevel minTraceLevel) {
106130
return traceLevel != null && traceLevel.ordinal() >= minTraceLevel.ordinal();
107131
}

src/main/java/org/prebid/server/activity/infrastructure/privacy/AbstainPrivacyModule.java renamed to src/main/java/org/prebid/server/activity/infrastructure/privacy/SkippedPrivacyModule.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
import java.util.Objects;
99

10-
public class AbstainPrivacyModule implements PrivacyModule, Loggable {
10+
public class SkippedPrivacyModule implements PrivacyModule, Loggable {
1111

1212
private final PrivacyModuleQualifier privacyModuleQualifier;
1313

14-
public AbstainPrivacyModule(PrivacyModuleQualifier privacyModuleQualifier) {
14+
public SkippedPrivacyModule(PrivacyModuleQualifier privacyModuleQualifier) {
1515
this.privacyModuleQualifier = Objects.requireNonNull(privacyModuleQualifier);
1616
}
1717

@@ -27,4 +27,8 @@ public JsonNode asLogEntry(ObjectMapper mapper) {
2727
.put("skipped", true)
2828
.put("result", Result.ABSTAIN.name());
2929
}
30+
31+
public PrivacyModuleQualifier skippedModule() {
32+
return privacyModuleQualifier;
33+
}
3034
}

src/main/java/org/prebid/server/activity/infrastructure/rule/AndRule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.prebid.server.activity.infrastructure.debug.Loggable;
99
import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
1010

11+
import java.util.Collections;
1112
import java.util.List;
1213
import java.util.Objects;
1314

@@ -45,4 +46,8 @@ public JsonNode asLogEntry(ObjectMapper mapper) {
4546

4647
return andNode;
4748
}
49+
50+
public List<Rule> rules() {
51+
return Collections.unmodifiableList(rules);
52+
}
4853
}

src/test/groovy/org/prebid/server/functional/tests/privacy/ActivityTraceLogSpec.groovy

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -509,11 +509,7 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec {
509509
}
510510

511511
where:
512-
code | defaultAction
513-
IAB_US_GENERAL | false
514-
IAB_US_GENERAL | true
515-
IAB_US_CUSTOM_LOGIC | false
516-
IAB_US_CUSTOM_LOGIC | true
512+
code << [IAB_US_GENERAL, IAB_US_CUSTOM_LOGIC]
517513
}
518514

519515
def "PBS auction should log consistently for each activity about skips modules in response"() {
@@ -675,6 +671,81 @@ class ActivityTraceLogSpec extends PrivacyBaseSpec {
675671
assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source
676672
}
677673

674+
def "PBS auction shouldn't log info about module skip in response when ext.prebid.trace=basic and skipRate is max"() {
675+
given: "Default bid request"
676+
def accountId = PBSUtils.randomNumber as String
677+
def bidRequest = getBidRequestWithPersonalData(accountId).tap {
678+
ext.prebid.trace = BASIC
679+
regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC
680+
regs.gppSid = [US_NAT_V1.intValue]
681+
}
682+
683+
and: "Set up activities"
684+
def condition = Condition.baseCondition.tap {
685+
it.gppSid = [US_NAT_V1.intValue]
686+
}
687+
def activityRule = ActivityRule.getDefaultActivityRule(condition).tap {
688+
it.privacyRegulation = [ALL]
689+
}
690+
def activity = Activity.getDefaultActivity([activityRule])
691+
def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity)
692+
693+
and: "Account gpp configuration"
694+
def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: MAX_PERCENT_AB)
695+
696+
and: "Save account with allow activities setup"
697+
def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig])
698+
accountDao.save(account)
699+
700+
when: "PBS processes auction requests"
701+
def bidResponse = activityPbsService.sendAuctionRequest(bidRequest)
702+
703+
then: "Generic bidder request should have data in EIDS fields"
704+
def genericBidderRequest = bidder.getBidderRequest(bidRequest.id)
705+
assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source
706+
707+
and: "Bid response should not contain info about rule configuration in debug"
708+
def infrastructure = bidResponse.ext.debug.trace.activityInfrastructure
709+
assert !findProcessingRule(infrastructure, TRANSMIT_EIDS).ruleConfiguration
710+
}
711+
712+
def "PBS auction shouldn't log info about module skip in response when ext.prebid.trace=null and skipRate is max"() {
713+
given: "Default bid request"
714+
def accountId = PBSUtils.randomNumber as String
715+
def bidRequest = getBidRequestWithPersonalData(accountId).tap {
716+
ext.prebid.trace = null
717+
regs.gpp = SIMPLE_GPC_DISALLOW_LOGIC
718+
regs.gppSid = [US_NAT_V1.intValue]
719+
}
720+
721+
and: "Set up activities"
722+
def condition = Condition.baseCondition.tap {
723+
it.gppSid = [US_NAT_V1.intValue]
724+
}
725+
def activityRule = ActivityRule.getDefaultActivityRule(condition).tap {
726+
it.privacyRegulation = [ALL]
727+
}
728+
def activity = Activity.getDefaultActivity([activityRule])
729+
def activities = AllowActivities.getDefaultAllowActivities(TRANSMIT_EIDS, activity)
730+
731+
and: "Account gpp configuration"
732+
def accountGppConfig = new AccountGppConfig(code: IAB_US_GENERAL, enabled: true, skipRate: MAX_PERCENT_AB)
733+
734+
and: "Save account with allow activities setup"
735+
def account = getAccountWithAllowActivitiesAndPrivacyModule(accountId, activities, [accountGppConfig])
736+
accountDao.save(account)
737+
738+
when: "PBS processes auction requests"
739+
def bidResponse = activityPbsService.sendAuctionRequest(bidRequest)
740+
741+
then: "Generic bidder request should have data in EIDS fields"
742+
def genericBidderRequest = bidder.getBidderRequest(bidRequest.id)
743+
assert genericBidderRequest.user.eids[0].source == bidRequest.user.eids[0].source
744+
745+
and: "Bid response should not contain info about trace"
746+
assert !bidResponse.ext.debug.trace
747+
}
748+
678749
private static List<ActivityInfrastructure> getActivityByName(List<ActivityInfrastructure> activityInfrastructures,
679750
ActivityType activity) {
680751
def firstIndex = activityInfrastructures.findLastIndexOf { it -> it.activity == activity }

src/test/java/org/prebid/server/activity/infrastructure/debug/ActivityInfrastructureDebugTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.prebid.server.activity.Activity;
1010
import org.prebid.server.activity.ComponentType;
1111
import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
12+
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
13+
import org.prebid.server.activity.infrastructure.privacy.SkippedPrivacyModule;
14+
import org.prebid.server.activity.infrastructure.rule.AndRule;
1215
import org.prebid.server.activity.infrastructure.rule.Rule;
1316
import org.prebid.server.activity.infrastructure.rule.TestRule;
1417
import org.prebid.server.metric.Metrics;
@@ -18,6 +21,8 @@
1821
import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInvocationResult;
1922
import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityRule;
2023

24+
import java.util.List;
25+
2126
import static org.assertj.core.api.Assertions.assertThat;
2227
import static org.mockito.ArgumentMatchers.eq;
2328
import static org.mockito.BDDMockito.given;
@@ -156,6 +161,69 @@ public void emitProcessedRuleShouldReturnExpectedResultIfTraceLevelIsVerbose() {
156161
verifyNoMoreInteractions(metrics);
157162
}
158163

164+
@Test
165+
public void emitProcessedRuleShouldLogModuleWhenModuleIsSkipped() {
166+
// given
167+
final ActivityInfrastructureDebug debug = debug(TraceLevel.verbose);
168+
169+
// when
170+
debug.emitProcessedRule(new SkippedPrivacyModule(PrivacyModuleQualifier.US_NAT), Rule.Result.ABSTAIN);
171+
172+
// then
173+
assertThat(debug.skippedPrivacyModules()).containsExactly(PrivacyModuleQualifier.US_NAT);
174+
assertThat(debug.trace()).containsExactly(ExtTraceActivityRule.of(
175+
"Processing rule.",
176+
mapper.createObjectNode()
177+
.put("privacy_module", "iab.usgeneral")
178+
.put("skipped", true)
179+
.put("result", "ABSTAIN"),
180+
Rule.Result.ABSTAIN));
181+
verify(metrics).updateRequestsActivityProcessedRulesCount();
182+
verify(metrics).updateAccountActivityProcessedRulesCount(eq("accountId"));
183+
verifyNoMoreInteractions(metrics);
184+
}
185+
186+
@Test
187+
public void emitProcessedRuleShouldLogSkippedModuleWhenAndRuleHasAbstainModule() {
188+
// given
189+
final ActivityInfrastructureDebug debug = debug(TraceLevel.verbose);
190+
191+
// when
192+
debug.emitProcessedRule(
193+
new AndRule(List.of(new SkippedPrivacyModule(PrivacyModuleQualifier.US_NAT))),
194+
Rule.Result.ABSTAIN);
195+
196+
// then
197+
assertThat(debug.skippedPrivacyModules()).containsExactly(PrivacyModuleQualifier.US_NAT);
198+
assertThat(debug.trace()).containsExactly(ExtTraceActivityRule.of(
199+
"Processing rule.",
200+
mapper.createObjectNode().set("and", mapper.createArrayNode().add(mapper.createObjectNode()
201+
.put("privacy_module", "iab.usgeneral")
202+
.put("skipped", true)
203+
.put("result", "ABSTAIN"))),
204+
Rule.Result.ABSTAIN));
205+
verify(metrics).updateRequestsActivityProcessedRulesCount();
206+
verify(metrics).updateAccountActivityProcessedRulesCount(eq("accountId"));
207+
verifyNoMoreInteractions(metrics);
208+
}
209+
210+
@Test
211+
public void emitProcessedRuleShouldLogSkippedModuleWhenTraceLevelIsNull() {
212+
// given
213+
final ActivityInfrastructureDebug debug = debug(null);
214+
215+
// when
216+
debug.emitProcessedRule(
217+
new AndRule(List.of(new SkippedPrivacyModule(PrivacyModuleQualifier.US_NAT))),
218+
Rule.Result.ABSTAIN);
219+
220+
// then
221+
assertThat(debug.skippedPrivacyModules()).containsExactly(PrivacyModuleQualifier.US_NAT);
222+
assertThat(debug.trace()).isEmpty();
223+
verify(metrics).updateRequestsActivityProcessedRulesCount();
224+
verifyNoMoreInteractions(metrics);
225+
}
226+
159227
@Test
160228
public void emitActivityInvocationResultShouldDoNothingIfTraceLevelIsNullAndActivityAllowed() {
161229
// given

0 commit comments

Comments
 (0)