-
Notifications
You must be signed in to change notification settings - Fork 769
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
EEA countries account-level override #4118
EEA countries account-level override #4118
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bsardo Configs that can be overridden at the account level are stored in the host level default account object. However, in this case the EEA Countries list is part of a different config area. Curious on your thoughts. Should the current location be deprecated in favor of account level?
exchange/exchange.go
Outdated
@@ -316,8 +316,17 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog | |||
|
|||
recordImpMetrics(r.BidRequestWrapper, e.me) | |||
|
|||
// Retrieve host and account-level EEA countries config | |||
eeaCountries := SelectEEACountries(e.privacyConfig.GDPR.EEACountries, r.Account.EEACountries) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: The comment is not necessary. The inputs are clearly host and account level, but if you'd like to make that association clearer consider a revised method name.
exchange/exchange.go
Outdated
eeaCountries := SelectEEACountries(e.privacyConfig.GDPR.EEACountries, r.Account.EEACountries) | ||
|
||
// Create a map for efficient lookup | ||
eeaCountriesMap := make(map[string]struct{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The performance benefit of a map only comes into play when the map is used more than once. As it is now, this map is only referenced once in parseGDPRDefaultValue
. This forces the processing of every element with the overhead of map creation. It would be more efficient to use a linear search in this instance.
Eventually, this map can live in the account config object when that caching layer is improved. Doesn't make sense there right now though.
config/account.go
Outdated
@@ -381,3 +382,12 @@ func (ip *IPv4) Validate(errs []error) []error { | |||
} | |||
return errs | |||
} | |||
|
|||
func (a *Account) ValidateEEACountries(errs []error) []error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation method is not called.
config/account.go
Outdated
@@ -42,6 +42,7 @@ type Account struct { | |||
DefaultBidLimit int `mapstructure:"default_bid_limit" json:"default_bid_limit"` | |||
BidAdjustments *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"` | |||
Privacy AccountPrivacy `mapstructure:"privacy" json:"privacy"` | |||
EEACountries []string `mapstructure:"eea_countries" json:"eea_countries"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be better to include this within the AccountGDPR object since it's only used for GDPR enforcement and to match the host configuration of .privacy.gdpr. eea_countries
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Let's move it down a level as suggested.
I agree we should deprecate it but my thought is that this should be done as part of a major release and should involve moving all GDPR fields (e.g. the purpose configs) that can be overridden at the account level to the account defaults object. In that case, I suggest we proceed with the approach Peter has taken here for now and perhaps consider this change for 4.0 or 5.0. |
exchange/exchange.go
Outdated
var accountEEACountries []string | ||
if r.Account.GDPR.EEACountries != nil { | ||
accountEEACountries = r.Account.GDPR.EEACountries | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this. You can just pass r.Account.GDPR.EEACountries
into SelectEEACountries
as the second parameter. If it's passed in as nil that should be ok.
exchange/exchange.go
Outdated
accountEEACountries = r.Account.GDPR.EEACountries | ||
} | ||
|
||
// Retrieve host and account-level EEA countries config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment should be tweaked a bit since it doesn't retrieve both host and account level configs but rather either host or account.
exchange/exchange.go
Outdated
@@ -584,7 +592,7 @@ func (e *exchange) parseGDPRDefaultValue(r *openrtb_ext.RequestWrapper) gdpr.Sig | |||
if geo != nil { | |||
// If we have a country set, and it is on the list, we assume GDPR applies if not set on the request. | |||
// Otherwise we assume it does not apply as long as it appears "valid" (is 3 characters long). | |||
if _, found := e.privacyConfig.GDPR.EEACountriesMap[strings.ToUpper(geo.Country)]; found { | |||
if _, found := e.privacyConfig.GDPR.EEACountriesMap[strings.ToUpper(geo.Country)]; found || isEEACountry(geo.Country, eeaCountries) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eeaCountries
contains either the account config or the host config. We need only check this selected config: if _, found := isEEACountry(geo.Country, eeaCountries) {
exchange/gdpr.go
Outdated
// If account-level configuration is provided, it takes precedence. | ||
if len(accountEEACountries) > 0 { | ||
return accountEEACountries | ||
} | ||
|
||
// Otherwise, return the host-level configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO you can remove these comments; the code is self-explanatory.
exchange/gdpr.go
Outdated
|
||
// SelectEEACountries selects the EEA countries based on host and account configurations. | ||
// Account-level configuration takes precedence over the host-level configuration. | ||
func SelectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function should be private (first letter should be lower case) as it is only used in the exchange package.
exchange/gdpr.go
Outdated
// Account-level configuration takes precedence over the host-level configuration. | ||
func SelectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { | ||
// If account-level configuration is provided, it takes precedence. | ||
if len(accountEEACountries) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than checking if there are any elements, I think we should check if accountEEACountries
is defined, in which case a not nil check would make more sense here.
exchange/exchange_test.go
Outdated
if result != tt.expected { | ||
t.Errorf("isEEACountry(%s, %v) = %v; want %v", tt.country, tt.eeaList, result, tt.expected) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use assert.Equal
instead.
exchange/exchange_test.go
Outdated
{"Country in EEA", "FRA", eeaCountries, true}, | ||
{"Country in EEA lowercase", "fra", eeaCountries, true}, | ||
{"Country not in EEA", "USA", eeaCountries, false}, | ||
{"Empty country string", "", eeaCountries, false}, | ||
{"EEA list is empty", "FRA", []string{}, false}, | ||
{"EEA list is nil", "FRA", nil, false}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explicitly specify each field name along with the value and put each field/value pair on its own line. The name
value should also be short with underscores used instead of spaces. t.Run
will automatically substitute underscores for spaces so we like to avoid spaces in our test case names so if a test fails we can do a quick search for the test name failure in our code base without having to do a space to underscore substitution.
For example:
{
name: "found_uppercase",
country: "FRA",
eeaList: eeaCountries,
expected: true,
},
exchange/gdpr.go
Outdated
|
||
// SelectEEACountries selects the EEA countries based on host and account configurations. | ||
// Account-level configuration takes precedence over the host-level configuration. | ||
func SelectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a simple unit test in exchange/gdpr_test.go
for this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add an exchange package JSON integration test so that we can verify HoldAuction
selects the correct EEA countries list. We can discuss this offline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a few test nitpicks.
exchange/gdpr_test.go
Outdated
expected []string | ||
}{ | ||
{ | ||
description: "Account EEA countries provided, return account's", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Use underscores instead of spaces when separating words in test name so t.Run
doesn't perform space for underscore substitutions making it easier to find failing tests in the code base via search.
exchange/gdpr_test.go
Outdated
expected []string | ||
}{ | ||
{ | ||
description: "Account EEA countries provided, return account's", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: I would also shorten your names removing the expected return info. That can easily be deciphered. Simply describing the inputs is recommended.
exchange/exchange_test.go
Outdated
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
result := isEEACountry(tt.country, tt.eeaList) | ||
assert.Equal(t, tt.expected, result, "isEEACountry(%s, %v)", tt.country, tt.eeaList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to assert.Equal(t, tt.expected, result)
. If this test fails, it will provide context on which test case fails making these last parameters unnecessary.
Implements #3678