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

GDPR: pass geo based on special feature 1 opt-in #2122

Merged
merged 4 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 32 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ type TCF2 struct {
Purpose8 TCF2Purpose `mapstructure:"purpose8"`
Purpose9 TCF2Purpose `mapstructure:"purpose9"`
Purpose10 TCF2Purpose `mapstructure:"purpose10"`
SpecialPurpose1 TCF2Purpose `mapstructure:"special_purpose1"`
SpecialFeature1 TCF2SpecialFeature `mapstructure:"special_feature1"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting. We were using the wrong terminology?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not just a matter of the wrong terminology. We are looking at the wrong field in the GVL. The go-gdpr package provides a vendor.SpecialPurpose method that checks if a special purpose is defined in the GVL specialPurposes field for a vendor. We are currently calling this method but that isn't correct. Instead we should be looking at GVL specialFeatures for a vendor. I have a go-gdpr PR out that is currently under review that will add a new method that allows us to access the correct field for a given vendor.

Copy link
Contributor

Choose a reason for hiding this comment

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

That'a concerning. What's the difference between a special purpose and a special feature? The TCF folks could've done better in the naming there.

PurposeOneTreatment TCF2PurposeOneTreatment `mapstructure:"purpose_one_treatment"`
}

Expand All @@ -301,6 +301,13 @@ type TCF2Purpose struct {
VendorExceptionMap map[openrtb_ext.BidderName]struct{}
}

type TCF2SpecialFeature struct {
Enforce bool `mapstructure:"enforce"`
// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
VendorExceptions []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"`
VendorExceptionMap map[openrtb_ext.BidderName]struct{}
}

type TCF2PurposeOneTreatment struct {
Enabled bool `mapstructure:"enabled"`
AccessAllowed bool `mapstructure:"access_allowed"`
Expand Down Expand Up @@ -556,7 +563,6 @@ func New(v *viper.Viper) (*Configuration, error) {
&c.GDPR.TCF2.Purpose8,
&c.GDPR.TCF2.Purpose9,
&c.GDPR.TCF2.Purpose10,
&c.GDPR.TCF2.SpecialPurpose1,
}
for c := 0; c < len(purposeConfigs); c++ {
purposeConfigs[c].VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{})
Expand All @@ -567,6 +573,14 @@ func New(v *viper.Viper) (*Configuration, error) {
}
}

// To look for a special feature's vendor exceptions in O(1) time, we fill this hash table with bidders located in the
// VendorExceptions field of the GDPR.TCF2.SpecialFeature1 struct defined in this file
c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{})
for v := 0; v < len(c.GDPR.TCF2.SpecialFeature1.VendorExceptions); v++ {
bidderName := c.GDPR.TCF2.SpecialFeature1.VendorExceptions[v]
c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap[bidderName] = struct{}{}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please verify this code has full test coverage for cases of none, one, and many (2). It's been a problem for us in the past.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍 Done


// To look for a request's app_id in O(1) time, we fill this hash table located in the
// the BlacklistedApps field of the Configuration struct defined in this file
c.BlacklistedAppMap = make(map[string]bool)
Expand Down Expand Up @@ -950,8 +964,6 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("gdpr.tcf2.purpose8.vendor_exceptions", []openrtb_ext.BidderName{})
v.SetDefault("gdpr.tcf2.purpose9.vendor_exceptions", []openrtb_ext.BidderName{})
v.SetDefault("gdpr.tcf2.purpose10.vendor_exceptions", []openrtb_ext.BidderName{})
v.SetDefault("gdpr.tcf2.special_purpose1.enabled", true)
v.SetDefault("gdpr.tcf2.special_purpose1.vendor_exceptions", []openrtb_ext.BidderName{})
v.SetDefault("gdpr.amp_exception", false)
v.SetDefault("gdpr.eea_countries", []string{"ALA", "AUT", "BEL", "BGR", "HRV", "CYP", "CZE", "DNK", "EST",
"FIN", "FRA", "GUF", "DEU", "GIB", "GRC", "GLP", "GGY", "HUN", "ISL", "IRL", "IMN", "ITA", "JEY", "LVA",
Expand Down Expand Up @@ -1008,6 +1020,7 @@ func SetupViper(v *viper.Viper, filename string) {
// Migrate config settings to maintain compatibility with old configs
migrateConfig(v)
migrateConfigPurposeOneTreatment(v)
migrateConfigSpecialFeature1(v)
migrateConfigTCF2PurposeEnabledFlags(v)

// These defaults must be set after the migrate functions because those functions look for the presence of these
Expand Down Expand Up @@ -1035,6 +1048,8 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("gdpr.tcf2.purpose10.enforce_purpose", TCF2FullEnforcement)
v.SetDefault("gdpr.tcf2.purpose_one_treatment.enabled", true)
v.SetDefault("gdpr.tcf2.purpose_one_treatment.access_allowed", true)
v.SetDefault("gdpr.tcf2.special_feature1.enforce", true)
v.SetDefault("gdpr.tcf2.special_feature1.vendor_exceptions", []openrtb_ext.BidderName{})
}

func migrateConfig(v *viper.Viper) {
Expand Down Expand Up @@ -1062,6 +1077,19 @@ func migrateConfigPurposeOneTreatment(v *viper.Viper) {
}
}

func migrateConfigSpecialFeature1(v *viper.Viper) {
if oldConfig, ok := v.Get("gdpr.tcf2.special_purpose1").(map[string]interface{}); ok {
if v.IsSet("gdpr.tcf2.special_feature1") {
glog.Warning("using gdpr.tcf2.special_feature1 and ignoring deprecated gdpr.tcf2.special_purpose1")
} else {
glog.Warning("gdpr.tcf2.special_purpose1.enabled is deprecated and should be changed to gdpr.tcf2.special_feature1.enforce")
glog.Warning("gdpr.tcf2.special_purpose1.vendor_exceptions is deprecated and should be changed to gdpr.tcf2.special_feature1.vendor_exceptions")
v.Set("gdpr.tcf2.special_feature1.enforce", oldConfig["enabled"])
v.Set("gdpr.tcf2.special_feature1.vendor_exceptions", oldConfig["vendor_exceptions"])
}
}
}

func migrateConfigTCF2PurposeEnabledFlags(v *viper.Viper) {
for i := 1; i <= 10; i++ {
oldField := fmt.Sprintf("gdpr.tcf2.purpose%d.enabled", i)
Expand Down
150 changes: 145 additions & 5 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ func TestDefaults(t *testing.T) {
VendorExceptions: []openrtb_ext.BidderName{},
VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
},
SpecialPurpose1: TCF2Purpose{
Enabled: true,
SpecialFeature1: TCF2SpecialFeature{
Enforce: true,
VendorExceptions: []openrtb_ext.BidderName{},
VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
},
Expand Down Expand Up @@ -272,7 +272,7 @@ gdpr:
purpose10:
enforce_vendors: false
vendor_exceptions: ["foo10"]
special_purpose1:
special_feature1:
vendor_exceptions: ["fooSP1"]
ccpa:
enforce: true
Expand Down Expand Up @@ -540,8 +540,8 @@ func TestFullConfig(t *testing.T) {
VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo10")},
VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo10"): {}},
},
SpecialPurpose1: TCF2Purpose{
Enabled: true, // true by default
SpecialFeature1: TCF2SpecialFeature{
Enforce: true, // true by default
VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("fooSP1")},
VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("fooSP1"): {}},
},
Expand Down Expand Up @@ -765,6 +765,91 @@ func TestMigrateConfigPurposeOneTreatment(t *testing.T) {
}
}

func TestMigrateConfigSpecialFeature1(t *testing.T) {
oldSpecialFeature1Config := []byte(`
gdpr:
tcf2:
special_purpose1:
enabled: true
vendor_exceptions: ["appnexus"]
`)
newSpecialFeature1Config := []byte(`
gdpr:
tcf2:
special_feature1:
enforce: true
vendor_exceptions: ["appnexus"]
`)
oldAndNewSpecialFeature1Config := []byte(`
gdpr:
tcf2:
special_purpose1:
enabled: false
vendor_exceptions: ["appnexus"]
special_feature1:
enforce: true
vendor_exceptions: ["rubicon"]
`)

tests := []struct {
description string
config []byte
wantSpecialFeature1Enforce bool
wantSpecialFeature1VendorExceptions []string
}{
{
description: "New config and old config not set",
config: []byte{},
},
{
description: "New config not set, old config set",
config: oldSpecialFeature1Config,
wantSpecialFeature1Enforce: true,
wantSpecialFeature1VendorExceptions: []string{"appnexus"},
},
{
description: "New config set, old config not set",
config: newSpecialFeature1Config,
wantSpecialFeature1Enforce: true,
wantSpecialFeature1VendorExceptions: []string{"appnexus"},
},
{
description: "New config and old config set",
config: oldAndNewSpecialFeature1Config,
wantSpecialFeature1Enforce: true,
wantSpecialFeature1VendorExceptions: []string{"rubicon"},
},
}

for _, tt := range tests {
v := viper.New()
v.SetConfigType("yaml")
v.ReadConfig(bytes.NewBuffer(tt.config))

migrateConfigSpecialFeature1(v)

if len(tt.config) > 0 {
assert.Equal(t, tt.wantSpecialFeature1Enforce, v.Get("gdpr.tcf2.special_feature1.enforce").(bool), tt.description)
assert.Equal(t, tt.wantSpecialFeature1VendorExceptions, v.GetStringSlice("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
} else {
assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.enforce"), tt.description)
assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I find this to be a very comprehensive test case but: can we make one last assertion in the resulting Configuration object itself? I realize TestSpecialFeature1VendorExceptionMap does this to an extent but not when oldSpecialFeature1Config is set. Maybe we could add an v.Unmarshal() call at the end of this test case so we assert that cfg.GDPR.TCF2.SpecialFeature1 was correctly set even when gdpr.tcf2.special_purpose1 is set as in oldSpecialFeature1Config.

824     for _, tt := range tests {
825         v := viper.New()
826         v.SetConfigType("yaml")
827         v.ReadConfig(bytes.NewBuffer(tt.config))
828
829         migrateConfigSpecialFeature1(v)
830
831         if len(tt.config) > 0 {
832             assert.Equal(t, tt.wantSpecialFeature1Enforce, v.Get("gdpr.tcf2.special_feature1.enforce").(bool), tt.description)
833             assert.Equal(t, tt.wantSpecialFeature1VendorExceptions, v.GetStringSlice("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
834         } else {
835             assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.enforce"), tt.description)
836             assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
837         }
    +
    +	    var c Configuration
    +       err := v.Unmarshal(&c)
    +       assert.NoError(t, err, tt.desc)
    +
    +       // Assert expected values on the `cfg.GDPR.TCF2.SpecialFeature1` object itself
    +       assert.Equal(t, tt.wantSpecialFeature1Enforce, cfg.GDPR.TCF2.SpecialFeature1.Enforce, tt.desc)
    +       assert.ElementsMatch(t, tt.wantSpecialFeature1VendorExceptions, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptions, tt.desc)
838     }
config/config_test.go

Or even better, a New(v) call so we can also assert the correctness of the cfg.GDPR.TCF2.SpecialFeature1.VendorExceptionMap

824     for _, tt := range tests {
825         v := viper.New()
826         v.SetConfigType("yaml")
827         v.ReadConfig(bytes.NewBuffer(tt.config))
828
829         migrateConfigSpecialFeature1(v)
830
831         if len(tt.config) > 0 {
832             assert.Equal(t, tt.wantSpecialFeature1Enforce, v.Get("gdpr.tcf2.special_feature1.enforce").(bool), tt.description)
833             assert.Equal(t, tt.wantSpecialFeature1VendorExceptions, v.GetStringSlice("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
834         } else {
835             assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.enforce"), tt.description)
836             assert.Nil(t, v.Get("gdpr.tcf2.special_feature1.vendor_exceptions"), tt.description)
837         }
    +
    +	    cfg := New(v)
    +
    +       // Assert expected values on the `cfg.GDPR.TCF2.SpecialFeature1` object itself
    +       assert.Equal(t, tt.wantSpecialFeature1Enforce, cfg.GDPR.TCF2.SpecialFeature1.Enforce, tt.desc)
    +       assert.ElementsMatch(t, tt.wantSpecialFeature1VendorExceptions, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptions, tt.desc)
    +       assert.Equal(t, tt.wantSpecialFeature1VendorExceptionsMap, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptionMap, tt.desc)
838     }
config/config_test.go

Another option is to probably add an oldSpecialFeature1Config scenatio to TestSpecialFeature1VendorExceptionMap? What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@guscarreon and I spoke offline about this.

My line of thinking was that the coverage was there across three unit tests but it was hard to see:
TestMigrateConfigSpecialFeature1 —> verifies the deprecated special purpose config values are properly mapped to the new special feature config values
TestFullConfig —> verifies all of the special purpose struct fields, including the vendor exception map, are correctly populated based on what’s set in the special feature config values
TestSpecialFeature1VendorExceptionMap —> verifies the vendor exception map is created correctly no matter how many elements are in the vendor exception slice

I'm hesitant to make use of another function in the package to perform assertions in a pure unit test so instead of calling New() we agreed to call unmarshal as a happy medium to ensure what's written to the viper config in the migrate function is able to be unmarshaled into the struct.


var c Configuration
err := v.Unmarshal(&c)
assert.NoError(t, err, tt.description)
assert.Equal(t, tt.wantSpecialFeature1Enforce, c.GDPR.TCF2.SpecialFeature1.Enforce, tt.description)

// convert expected vendor exceptions to type BidderName
expectedVendorExceptions := make([]openrtb_ext.BidderName, 0, 0)
for _, ve := range tt.wantSpecialFeature1VendorExceptions {
expectedVendorExceptions = append(expectedVendorExceptions, openrtb_ext.BidderName(ve))
}
assert.ElementsMatch(t, expectedVendorExceptions, c.GDPR.TCF2.SpecialFeature1.VendorExceptions, tt.description)
}
}

func TestMigrateConfigTCF2PurposeEnabledFlags(t *testing.T) {
trueStr := "true"
falseStr := "false"
Expand Down Expand Up @@ -1291,3 +1376,58 @@ func doTimeoutTest(t *testing.T, expected int, requested int, max uint64, def ui
limited := cfg.LimitAuctionTimeout(time.Duration(requested) * time.Millisecond)
assert.Equal(t, limited, expectedDuration, "Expected %dms timeout, got %dms", expectedDuration, limited/time.Millisecond)
}

func TestSpecialFeature1VendorExceptionMap(t *testing.T) {
baseConfig := []byte(`
gdpr:
default_value: 0
tcf2:
special_feature1:
vendor_exceptions: `)

tests := []struct {
description string
configVendorExceptions []byte
wantVendorExceptions []openrtb_ext.BidderName
wantVendorExceptionsMap map[openrtb_ext.BidderName]struct{}
}{
{
description: "nil vendor exceptions",
configVendorExceptions: []byte(`null`),
wantVendorExceptions: []openrtb_ext.BidderName{},
wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{},
},
{
description: "no vendor exceptions",
configVendorExceptions: []byte(`[]`),
wantVendorExceptions: []openrtb_ext.BidderName{},
wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{},
},
{
description: "one vendor exception",
configVendorExceptions: []byte(`["vendor1"]`),
wantVendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("vendor1")},
wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("vendor1"): {}},
},
{
description: "many exceptions",
configVendorExceptions: []byte(`["vendor1","vendor2"]`),
wantVendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("vendor1"), openrtb_ext.BidderName("vendor2")},
wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("vendor1"): {}, openrtb_ext.BidderName("vendor2"): {}},
},
}

for _, tt := range tests {
config := append(baseConfig, tt.configVendorExceptions...)

v := viper.New()
SetupViper(v, "")
v.SetConfigType("yaml")
v.ReadConfig(bytes.NewBuffer(config))
cfg, err := New(v)
assert.NoError(t, err, "Setting up config error", tt.description)

assert.Equal(t, tt.wantVendorExceptions, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptions, tt.description)
assert.Equal(t, tt.wantVendorExceptionsMap, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptionMap, tt.description)
}
}
10 changes: 5 additions & 5 deletions gdpr/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16,
return
}

if p.cfg.TCF2.SpecialPurpose1.Enabled {
vendorException := p.isSpecialPurposeVendorException(bidder)
passGeo = vendorException || (consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialPurpose(1) || weakVendorEnforcement))
if p.cfg.TCF2.SpecialFeature1.Enforce {
vendorException := p.isSpecialFeatureVendorException(bidder)
passGeo = vendorException || (consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialFeature(1) || weakVendorEnforcement))
} else {
passGeo = true
}
Expand Down Expand Up @@ -162,8 +162,8 @@ func (p *permissionsImpl) isVendorException(purpose consentconstants.Purpose, bi
return
}

func (p *permissionsImpl) isSpecialPurposeVendorException(bidder openrtb_ext.BidderName) (vendorException bool) {
if _, ok := p.cfg.TCF2.SpecialPurpose1.VendorExceptionMap[bidder]; ok {
func (p *permissionsImpl) isSpecialFeatureVendorException(bidder openrtb_ext.BidderName) (vendorException bool) {
if _, ok := p.cfg.TCF2.SpecialFeature1.VendorExceptionMap[bidder]; ok {
vendorException = true
}
return
Expand Down
24 changes: 12 additions & 12 deletions gdpr/impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ func buildVendorList34() vendorList {
ID: 6,
Purposes: []int{1, 2, 4},
LegIntPurposes: []int{7},
SpecialPurposes: []int{1},
SpecialFeatures: []int{1},
FlexiblePurposes: []int{1, 2, 4, 7},
},
"8": {
Expand All @@ -352,7 +352,7 @@ func buildVendorList34() vendorList {
"10": {
ID: 10,
Purposes: []int{2, 4, 7},
SpecialPurposes: []int{1},
SpecialFeatures: []int{1},
},
"20": {
ID: 20,
Expand Down Expand Up @@ -384,7 +384,7 @@ func allPurposesEnabledPermissions() (perms permissionsImpl) {
Purpose8: config.TCF2Purpose{EnforcePurpose: config.TCF2FullEnforcement, EnforceVendors: true},
Purpose9: config.TCF2Purpose{EnforcePurpose: config.TCF2FullEnforcement, EnforceVendors: true},
Purpose10: config.TCF2Purpose{EnforcePurpose: config.TCF2FullEnforcement, EnforceVendors: true},
SpecialPurpose1: config.TCF2Purpose{Enabled: true, EnforceVendors: true},
SpecialFeature1: config.TCF2SpecialFeature{Enforce: true},
},
},
}
Expand Down Expand Up @@ -431,7 +431,7 @@ func TestAllowActivitiesGeoAndID(t *testing.T) {
}),
}

// COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes and vendors 2, 6, 8
// COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes and vendors 2, 6, 8 and special feature 1 opt-in
testDefs := []testDef{
{
description: "Appnexus vendor test, insufficient purposes claimed",
Expand Down Expand Up @@ -536,7 +536,7 @@ func TestAllowActivitiesPubRestrict(t *testing.T) {
}

// COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA - vendors 1-10 legit interest only,
// Pub restriction on purpose 7, consent only ... no allowPI will pass, no Special purpose 1 consent
// Pub restriction on purpose 7, consent only ... no allowPI will pass, no special feature 1 consent
testDefs := []testDef{
{
description: "Appnexus vendor test, insufficient purposes claimed",
Expand Down Expand Up @@ -840,7 +840,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
testDefs := []struct {
description string
p2VendorExceptionMap map[openrtb_ext.BidderName]struct{}
sp1VendorExceptionMap map[openrtb_ext.BidderName]struct{}
sf1VendorExceptionMap map[openrtb_ext.BidderName]struct{}
bidder openrtb_ext.BidderName
consent string
allowBid bool
Expand All @@ -859,27 +859,27 @@ func TestAllowActivitiesVendorException(t *testing.T) {
{
description: "Bid/ID allowed by vendor exception - p2 enabled with p2 vendor exception, pub restricts none",
p2VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
bidder: openrtb_ext.BidderAppnexus,
consent: noPurposeOrVendorConsentAndPubRestrictsNone,
allowBid: true,
passGeo: false,
passID: true,
},
{
description: "Geo blocked - sp1 enabled but no consent",
description: "Geo blocked - sf1 enabled but no consent",
p2VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
bidder: openrtb_ext.BidderAppnexus,
consent: noPurposeOrVendorConsentAndPubRestrictsNone,
allowBid: false,
passGeo: false,
passID: false,
},
{
description: "Geo allowed by vendor exception - sp1 enabled with sp1 vendor exception",
description: "Geo allowed by vendor exception - sf1 enabled with sf1 vendor exception",
p2VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
bidder: openrtb_ext.BidderAppnexus,
consent: noPurposeOrVendorConsentAndPubRestrictsNone,
allowBid: false,
Expand All @@ -896,7 +896,7 @@ func TestAllowActivitiesVendorException(t *testing.T) {
TCF2: config.TCF2{
Enabled: true,
Purpose2: config.TCF2Purpose{EnforcePurpose: config.TCF2FullEnforcement, VendorExceptionMap: td.p2VendorExceptionMap},
SpecialPurpose1: config.TCF2Purpose{Enabled: true, VendorExceptionMap: td.sp1VendorExceptionMap},
SpecialFeature1: config.TCF2SpecialFeature{Enforce: true, VendorExceptionMap: td.sf1VendorExceptionMap},
},
},
vendorIDs: map[openrtb_ext.BidderName]uint16{
Expand Down
Loading