Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPP4.5: Functional tests for custom logic functionality #2494

Merged
merged 19 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8c541da
Add GPP4.5: Functional tests for custom logic functionality
osulzhenko Jul 10, 2023
9aea823
Update normalizing for age restriction
osulzhenko Sep 11, 2023
639cb04
Update jsonLogic formatting
osulzhenko Sep 18, 2023
fb05a2c
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 18, 2023
1e4dceb
Refactor custom logic and remove `shouldBeEqual` property
osulzhenko Sep 18, 2023
c9f6e45
Update after review
osulzhenko Sep 18, 2023
8300b16
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 18, 2023
2c84835
Update warning tests and activity config default
osulzhenko Sep 19, 2023
9cc916a
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 19, 2023
a9b10d8
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 19, 2023
9c8d691
Rework normalize and update test cases
osulzhenko Sep 19, 2023
d292aa5
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 19, 2023
cd3c578
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 20, 2023
493f1a9
Fix test issue
osulzhenko Sep 20, 2023
ea76303
Update due to provided comments
osulzhenko Sep 20, 2023
4ed6efd
Update due to provided comments
osulzhenko Sep 20, 2023
945a856
Merge branch 'add-custom-logic-privacy-module' into tests-gpp-custom-…
osulzhenko Sep 20, 2023
ced08cf
Update error message for JsonLogic exception
osulzhenko Sep 20, 2023
e135591
Minnor fix
osulzhenko Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.prebid.server.functional.model.config

import groovy.transform.ToString
import org.prebid.server.functional.model.request.auction.ActivityType

import static org.prebid.server.functional.model.config.DataActivity.INVALID
import static org.prebid.server.functional.model.config.LogicalRestrictedRule.LogicalOperation.OR
import static org.prebid.server.functional.model.config.UsNationalPrivacySection.GPC

@ToString(includeNames = true, ignoreNulls = true)
class ActivityConfig {

List<ActivityType> activities
LogicalRestrictedRule restrictIfTrue

ActivityConfig() {
}

ActivityConfig(List<ActivityType> activities, LogicalRestrictedRule restrictIfTrue) {
this.activities = activities
this.restrictIfTrue = restrictIfTrue
}

static ActivityConfig getConfigWithDefaultRestrictRules(List<ActivityType> activities = ActivityType.values()) {
new ActivityConfig().tap {
it.activities = activities
it.restrictIfTrue = LogicalRestrictedRule.generateSolidRestriction(OR, [new InequalityValueRule(GPC, INVALID)])
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.annotation.JsonValue

enum DataActivity {

NOT_APPLICABLE(0),
NOTICE_PROVIDED(1),
NOTICE_NOT_PROVIDED(2),
NO_CONSENT(1),
CONSENT(2),
INVALID(-1),

@JsonValue
final int dataActivityBits

DataActivity(int dataActivityBits) {
this.dataActivityBits = dataActivityBits
}

static DataActivity fromInt(int dataActivityBits) {
values().find { it.dataActivityBits == dataActivityBits }
?: { throw new IllegalArgumentException("Invalid dataActivityBits: ${dataActivityBits}") }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.core.JacksonException
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import groovy.transform.ToString

@ToString(includeNames = true, ignoreNulls = true)
@JsonDeserialize(using = EqualityValueRuleDeserialize.class)
class EqualityValueRule extends ValueRestrictedRule{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntax


EqualityValueRule(UsNationalPrivacySection privacySection, DataActivity value) {
super(privacySection, value)
}

static class EqualityValueRuleDeserialize extends JsonDeserializer<EqualityValueRule> {

@Override
EqualityValueRule deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser)
def privacySection = UsNationalPrivacySection.valueFromText(node.get(0).get(JSON_LOGIC_VALUE_FIELD).textValue())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to use null-safe reference in this and related classes.
Example: node?.get(0)?.get(JSON_LOGIC_VALUE_FIELD)?.textValue()

def value = DataActivity.fromInt(node.get(1).asInt())
return new EqualityValueRule(privacySection, value)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.core.JacksonException
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import groovy.transform.ToString

@ToString(includeNames = true, ignoreNulls = true)
@JsonDeserialize(using = InequalityValueRuleDeserialize.class)
class InequalityValueRule extends ValueRestrictedRule {

InequalityValueRule(UsNationalPrivacySection privacySection, DataActivity value) {
super(privacySection, value)
}

static class InequalityValueRuleDeserialize extends JsonDeserializer<InequalityValueRule> {

@Override
InequalityValueRule deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser)
def privacySection = UsNationalPrivacySection.valueFromText(node.get(0).get(JSON_LOGIC_VALUE_FIELD).textValue())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same about null-safety as in previous comment.

def value = DataActivity.fromInt(node.get(1).asInt())
return new InequalityValueRule(privacySection, value)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.annotation.JsonProperty
import groovy.transform.ToString

@ToString(includeNames = false, ignoreNulls = true)
class LogicalRestrictedRule {

@JsonProperty("==")
EqualityValueRule equalRule
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be consistent with the naming. Looks like this should be called equalityRule


@JsonProperty("!=")
InequalityValueRule inequalityRule

List<LogicalRestrictedRule> or
List<LogicalRestrictedRule> and

LogicalRestrictedRule(ValueRestrictedRule valueOperation) {
if (valueOperation instanceof EqualityValueRule) {
equalRule = valueOperation
} else if (valueOperation instanceof InequalityValueRule) {
inequalityRule = valueOperation
}
}

private LogicalRestrictedRule() {
}

static getRootLogicalRestricted() {
new LogicalRestrictedRule()
}

static LogicalRestrictedRule generateSolidRestriction(LogicalOperation logicalOperator, List<ValueRestrictedRule> valueOperations) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does solid mean in this case?

Copy link
Collaborator Author

@osulzhenko osulzhenko Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used solid meaning that we will have a single logic rule with multiple valueRules. The name was changed to generateSingleRestrictedRule

valueOperations.inject(new LogicalRestrictedRule()) { logicalRestrictedRule, value ->
logicalRestrictedRule.includeSubRestriction(logicalOperator, value)
logicalRestrictedRule
}
}

LogicalRestrictedRule includeSubRestriction(LogicalOperation logicalOperation, LogicalRestrictedRule logicalRestrictedRule) {
if (logicalOperation == LogicalOperation.OR) {
or = (or ?: []) + logicalRestrictedRule
} else if (logicalOperation == LogicalOperation.AND) {
and = (and ?: []) + logicalRestrictedRule
}
this
}

LogicalRestrictedRule includeSubRestriction(LogicalOperation logicalOperation, ValueRestrictedRule valueOperation) {
includeSubRestriction(logicalOperation, new LogicalRestrictedRule(valueOperation))
}

enum LogicalOperation {
OR, AND
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ class ModuleConfig {

List<GppSectionId> sids
Boolean normalizeFlags
List<ActivityConfig> activityConfig

static ModuleConfig getDefaultModuleConfig(List<GppSectionId> sids = [GppSectionId.USP_NAT_V1],
static ModuleConfig getDefaultModuleConfig(ActivityConfig activityConfig = ActivityConfig.configWithDefaultRestrictRules,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a reason why parameter order doesn't correspond to the field order?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field order was changed due to multiple parameter uses. I adjusted the field order of the class.

List<GppSectionId> sids = [GppSectionId.USP_NAT_V1],
Boolean normalizeFlags = true) {
new ModuleConfig().tap {
it.sids = sids
it.normalizeFlags = normalizeFlags
it.activityConfig = [activityConfig]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.annotation.JsonValue
import com.iab.gpp.encoder.field.UspNatV1Field
import org.prebid.server.functional.util.PBSUtils

enum UsNationalPrivacySection {

SHARING_NOTICE(UspNatV1Field.SHARING_NOTICE),
SALE_OPT_OUT_NOTICE(UspNatV1Field.SALE_OPT_OUT_NOTICE),
SHARING_OPT_OUT_NOTICE(UspNatV1Field.SHARING_OPT_OUT_NOTICE),
TARGETED_ADVERTISING_OPT_OUT_NOTICE(UspNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE),
SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE(UspNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE),
SENSITIVE_DATA_LIMIT_USE_NOTICE(UspNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE),
SALE_OPT_OUT(UspNatV1Field.SALE_OPT_OUT),
SHARING_OPT_OUT(UspNatV1Field.SHARING_OPT_OUT),
TARGETED_ADVERTISING_OPT_OUT(UspNatV1Field.TARGETED_ADVERTISING_OPT_OUT),
SENSITIVE_DATA_RACIAL_ETHNIC_ORIGIN(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 1),
SENSITIVE_DATA_RELIGIOUS_BELIEFS(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 2),
SENSITIVE_DATA_HEALTH_INFO(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 3),
SENSITIVE_DATA_ORIENTATION(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 4),
SENSITIVE_DATA_CITIZENSHIP_STATUS(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 5),
SENSITIVE_DATA_GENETIC_ID(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 6),
SENSITIVE_DATA_BIOMETRIC_ID(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 7),
SENSITIVE_DATA_GEOLOCATION(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 8),
SENSITIVE_DATA_ID_NUMBERS(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 9),
SENSITIVE_DATA_ACCOUNT_INFO(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 10),
SENSITIVE_DATA_UNION_MEMBERSHIP(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 11),
SENSITIVE_DATA_COMMUNICATION_CONTENTS(UspNatV1Field.SENSITIVE_DATA_PROCESSING + 12),
SENSITIVE_DATA_PROCESSING_ALL(UspNatV1Field.SENSITIVE_DATA_PROCESSING + "*"),
CHILD_CONSENTS_FROM_13_TO_16(UspNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS + 1),
CHILD_CONSENTS_BELOW_13(UspNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS + 2),
PERSONAL_DATA_CONSENTS(UspNatV1Field.PERSONAL_DATA_CONSENTS),
MSPA_COVERED_TRANSACTION(UspNatV1Field.MSPA_COVERED_TRANSACTION),
MSPA_OPT_OUT_OPTION_MODE(UspNatV1Field.MSPA_OPT_OUT_OPTION_MODE),
MSPA_SERVICE_PROVIDER_MODE(UspNatV1Field.MSPA_SERVICE_PROVIDER_MODE),
GPC(UspNatV1Field.GPC);

@JsonValue
final String value

private UsNationalPrivacySection(String value) {
this.value = value
}

static UsNationalPrivacySection valueFromText(String value) {
values().find { section -> section.value.equalsIgnoreCase(value) }
?: { throw new IllegalArgumentException("Invalid UsNationalPrivacySection value: $value") }()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import groovy.transform.ToString

@ToString(includeNames = true, ignoreNulls = true)
@JsonSerialize(using = ValueRestrictedRuleSerializer.class)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class ValueRestrictedRule {

protected UsNationalPrivacySection privacySection
protected DataActivity value

protected static final String JSON_LOGIC_VALUE_FIELD = "var"

ValueRestrictedRule(UsNationalPrivacySection privacySection, DataActivity dataActivity) {
this.privacySection = privacySection
this.value = dataActivity
}

static class ValueRestrictedRuleSerializer extends JsonSerializer<ValueRestrictedRule> {

@Override
void serialize(ValueRestrictedRule valueRestrictedRule, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartArray()
jsonGenerator.writeStartObject()
jsonGenerator.writeStringField(JSON_LOGIC_VALUE_FIELD, valueRestrictedRule.privacySection.value)
jsonGenerator.writeEndObject()
jsonGenerator.writeObject(valueRestrictedRule.value.dataActivityBits)
jsonGenerator.writeEndArray()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
package org.prebid.server.functional.model.request.auction

import com.fasterxml.jackson.annotation.JsonValue

enum ActivityType {

SYNC_USER, FETCH_BIDS, ENRICH_UFPD, REPORT_ANALYTICS, TRANSMIT_UFPD, TRANSMIT_PRECISE_GEO
SYNC_USER("syncUser"),
FETCH_BIDS("fetchBids"),
ENRICH_UFPD("enrichUfpd"),
REPORT_ANALYTICS("reportAnalytics"),
TRANSMIT_UFPD("transmitUfpd"),
TRANSMIT_PRECISE_GEO("transmitPreciseGeo")

@JsonValue
String value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good habit is to have this kind of fields final


ActivityType(String value) {
this.value = value
}

String getMetricValue() {
name().toLowerCase()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum PrivacyModule {

IAB_TFC_EU("iab.tcfeu"),
IAB_US_GENERAL("iab.usgeneral"),
IAB_US_CUSTOM_LOGIC("iab.uscustomlogic"),
IAB_ALL("iab.*"),
CUSTOM_US_UTAH("custom.usutah"),
ALL("*")
Expand Down
Loading