Skip to content

Commit

Permalink
Update IsSyncerPriority logic
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexBVolcy committed Aug 17, 2023
1 parent 4891b4e commit bc8c72a
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 96 deletions.
17 changes: 4 additions & 13 deletions endpoints/setuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,8 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use
setSiteCookie := siteCookieCheck(r.UserAgent())

// Priority Ejector Set Up
if !isSyncerPriority(syncer.Key(), cfg.UserSync.PriorityGroups, syncersByBidder) {
err = errors.New("syncer key " + syncer.Key() + " is not in priority groups")
w.WriteHeader(http.StatusBadRequest)
metricsEngine.RecordSetUid(metrics.SetUidBadRequest)
so.Errors = []error{err}
so.Status = http.StatusBadRequest
return
}
priorityEjector := &usersync.PriorityBidderEjector{PriorityGroups: cfg.UserSync.PriorityGroups, TieEjector: &usersync.OldestEjector{}}
priorityEjector.IsSyncerPriority = isSyncerPriority(bidderName, cfg.UserSync.PriorityGroups)

// Write Cookie
encodedCookie, err := cookie.PrepareCookieForWrite(&cfg.HostCookie, encoder, priorityEjector)
Expand Down Expand Up @@ -346,13 +339,11 @@ func getSyncer(query url.Values, syncersByBidder map[string]usersync.Syncer) (us
return syncer, bidder, nil
}

func isSyncerPriority(syncer string, priorityGroups [][]string, syncersByBidder map[string]usersync.Syncer) bool {
func isSyncerPriority(bidderNameFromSyncerQuery string, priorityGroups [][]string) bool {
for _, group := range priorityGroups {
for _, bidder := range group {
if bidderSyncer, ok := syncersByBidder[bidder]; ok {
if syncer == bidderSyncer.Key() {
return true
}
if bidderNameFromSyncerQuery == bidder {
return true
}
}
}
Expand Down
77 changes: 18 additions & 59 deletions endpoints/setuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1333,92 +1333,49 @@ func TestGetResponseFormat(t *testing.T) {

func TestIsSyncerPriority(t *testing.T) {
testCases := []struct {
name string
givenSyncerKey string
givenPriorityGroups [][]string
givenSyncersByBidder map[string]usersync.Syncer
expected bool
name string
givenBidderNameFromSyncerQuery string
givenPriorityGroups [][]string
expected bool
}{
{
name: "syncer-is-priority-one-to-one",
givenSyncerKey: "prioritySyncer",
name: "bidder-name-is-priority",
givenBidderNameFromSyncerQuery: "priorityBidder",
givenPriorityGroups: [][]string{
{"prioritySyncer"},
{"priorityBidder"},
{"2", "3"},
},
givenSyncersByBidder: map[string]usersync.Syncer{
"prioritySyncer": fakeSyncer{
key: "prioritySyncer",
},
},
expected: true,
},
{
name: "syncer-is-priority-not-one-to-one",
givenSyncerKey: "adnxs",
givenPriorityGroups: [][]string{
{"appnexus"},
{"2", "3"},
},
givenSyncersByBidder: map[string]usersync.Syncer{
"appnexus": fakeSyncer{
key: "adnxs",
},
},
expected: true,
},
{
name: "syncer-is-not-priority",
givenSyncerKey: "notPrioritySyncer",
name: "bidder-name-is-not-priority",
givenBidderNameFromSyncerQuery: "notPriorityBidderName",
givenPriorityGroups: [][]string{
{"1"},
{"2", "3"},
},
givenSyncersByBidder: map[string]usersync.Syncer{
"1": fakeSyncer{
key: "1",
},
"2": fakeSyncer{
key: "2",
},
"3": fakeSyncer{
key: "3",
},
},
expected: false,
},
{
name: "no-syncer-given",
givenSyncerKey: "",
name: "no-bidder-name-given",
givenBidderNameFromSyncerQuery: "",
givenPriorityGroups: [][]string{
{"1"},
{"2", "3"},
},
givenSyncersByBidder: map[string]usersync.Syncer{
"1": fakeSyncer{
key: "1",
},
"2": fakeSyncer{
key: "2",
},
"3": fakeSyncer{
key: "3",
},
},
expected: false,
},
{
name: "no-priority-groups-given",
givenSyncerKey: "adnxs",
givenPriorityGroups: [][]string{},
givenSyncersByBidder: map[string]usersync.Syncer{},
expected: false,
name: "no-priority-groups-given",
givenBidderNameFromSyncerQuery: "bidderName",
givenPriorityGroups: [][]string{},
expected: false,
},
}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
isPriority := isSyncerPriority(test.givenSyncerKey, test.givenPriorityGroups, test.givenSyncersByBidder)
isPriority := isSyncerPriority(test.givenBidderNameFromSyncerQuery, test.givenPriorityGroups)
assert.Equal(t, test.expected, isPriority)
})
}
Expand Down Expand Up @@ -1485,6 +1442,8 @@ func doRequest(req *http.Request, analytics analytics.PBSAnalyticsModule, metric
syncersByBidder[bidderName] = fakeSyncer{key: syncerKey, defaultSyncType: usersync.SyncTypeIFrame}
if bidderName != "nonPriorityBidder" {
cfg.UserSync.PriorityGroups[0] = append(cfg.UserSync.PriorityGroups[0], bidderName)
} else {
cfg.HostCookie.MaxCookieSizeBytes = 100
}
}

Expand Down
76 changes: 57 additions & 19 deletions usersync/cookie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,15 +380,23 @@ func TestWriteCookieUserAgent(t *testing.T) {
func TestPrepareCookieForWrite(t *testing.T) {
encoder := Base64Encoder{}
decoder := Base64Decoder{}
cookieToSend := &Cookie{

mainCookie := &Cookie{
uids: map[string]UIDEntry{
"1": newTempId("1234567890123456789012345678901234567890123456", 7),
"7": newTempId("abcdefghijklmnopqrstuvwxy", 1),
"2": newTempId("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 6),
"3": newTempId("123456789012345678901234567896123456789012345678", 5),
"4": newTempId("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ", 4),
"5": newTempId("12345678901234567890123456789012345678901234567890", 3),
"6": newTempId("abcdefghij", 2),
"7": newTempId("abcdefghijklmnopqrstuvwxy", 1),
},
optOut: false,
}

errorCookie := &Cookie{
uids: map[string]UIDEntry{
"syncerNotPriority": newTempId("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 7),
},
optOut: false,
}
Expand Down Expand Up @@ -429,66 +437,96 @@ func TestPrepareCookieForWrite(t *testing.T) {
testCases := []struct {
name string
givenMaxCookieSize int
givenCookieToSend *Cookie
givenIsSyncerPriority bool
expectedRemainingUidKeys []string
expectedError error
}{
{
name: "no-uids-ejected",
givenMaxCookieSize: 2000,
name: "no-uids-ejected",
givenMaxCookieSize: 2000,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{
"1", "2", "3", "4", "5", "6", "7",
},
},
{
name: "no-uids-ejected-2",
givenMaxCookieSize: 0,
name: "no-uids-ejected-2",
givenMaxCookieSize: 0,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{
"1", "2", "3", "4", "5", "6", "7",
},
},
{
name: "one-uid-ejected",
givenMaxCookieSize: 900,
name: "one-uid-ejected",
givenMaxCookieSize: 900,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{
"1", "2", "3", "4", "5", "6",
},
},
{
name: "four-uids-ejected",
givenMaxCookieSize: 500,
name: "four-uids-ejected",
givenMaxCookieSize: 500,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{
"1", "2", "3",
},
},
{
name: "all-but-one-uids-ejected",
givenMaxCookieSize: 300,
name: "all-but-one-uids-ejected",
givenMaxCookieSize: 300,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{
"1",
},
},
{
name: "all-uids-ejected",
givenMaxCookieSize: 100,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{},
},
{
name: "invalid-max-size",
givenMaxCookieSize: -100,
givenCookieToSend: mainCookie,
givenIsSyncerPriority: true,
expectedRemainingUidKeys: []string{},
},
{
name: "syncer-is-not-priority",
givenMaxCookieSize: 100,
givenCookieToSend: errorCookie,
givenIsSyncerPriority: false,
expectedError: errors.New("syncer key is not a priority, and there are only priority elements left"),
},
}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
encodedCookie, err := cookieToSend.PrepareCookieForWrite(&config.HostCookie{MaxCookieSizeBytes: test.givenMaxCookieSize}, encoder, ejector)
assert.NoError(t, err)
decodedCookie := decoder.Decode(encodedCookie)
ejector.IsSyncerPriority = test.givenIsSyncerPriority
encodedCookie, err := test.givenCookieToSend.PrepareCookieForWrite(&config.HostCookie{MaxCookieSizeBytes: test.givenMaxCookieSize}, encoder, ejector)

if test.expectedError != nil {
assert.Equal(t, test.expectedError, err)
} else {
assert.NoError(t, err)
decodedCookie := decoder.Decode(encodedCookie)

for _, key := range test.expectedRemainingUidKeys {
_, ok := decodedCookie.uids[key]
assert.Equal(t, true, ok)
for _, key := range test.expectedRemainingUidKeys {
_, ok := decodedCookie.uids[key]
assert.Equal(t, true, ok)
}
assert.Equal(t, len(decodedCookie.uids), len(test.expectedRemainingUidKeys))
}
assert.Equal(t, len(decodedCookie.uids), len(test.expectedRemainingUidKeys))
})
}
}
Expand Down
12 changes: 9 additions & 3 deletions usersync/ejector.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package usersync

import (
"errors"
"time"
)

Expand All @@ -11,9 +12,10 @@ type Ejector interface {
type OldestEjector struct{}

type PriorityBidderEjector struct {
PriorityGroups [][]string
syncersByBidder map[string]Syncer
TieEjector Ejector
PriorityGroups [][]string
syncersByBidder map[string]Syncer
IsSyncerPriority bool
TieEjector Ejector
}

// Choose method for oldest ejector will return the oldest uid
Expand All @@ -33,6 +35,10 @@ func (o *OldestEjector) Choose(uids map[string]UIDEntry) (string, error) {
// Choose method for priority ejector will return the oldest lowest priority element
func (p *PriorityBidderEjector) Choose(uids map[string]UIDEntry) (string, error) {
nonPriortyUids := getNonPriorityUids(uids, p.PriorityGroups, p.syncersByBidder)
if len(nonPriortyUids) == 1 && !p.IsSyncerPriority {
return "", errors.New("syncer key is not a priority, and there are only priority elements left")
}

if len(nonPriortyUids) > 0 {
return p.TieEjector.Choose(nonPriortyUids)
}
Expand Down
34 changes: 32 additions & 2 deletions usersync/ejector_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package usersync

import (
"errors"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -41,6 +42,7 @@ func TestPriorityEjector(t *testing.T) {
key: "lowestPriority",
},
},
IsSyncerPriority: true,
},
expected: "lowestPriority",
},
Expand Down Expand Up @@ -68,7 +70,8 @@ func TestPriorityEjector(t *testing.T) {
key: "olderButSamePriority",
},
},
TieEjector: &OldestEjector{},
IsSyncerPriority: true,
TieEjector: &OldestEjector{},
},
expected: "olderButSamePriority",
},
Expand Down Expand Up @@ -111,7 +114,8 @@ func TestPriorityEjector(t *testing.T) {
key: "newestNonPriority",
},
},
TieEjector: &OldestEjector{},
IsSyncerPriority: true,
TieEjector: &OldestEjector{},
},
expected: "oldestNonPriority",
},
Expand All @@ -132,9 +136,35 @@ func TestPriorityEjector(t *testing.T) {
key: "onlyPriorityElement",
},
},
IsSyncerPriority: true,
},
expected: "onlyPriorityElement",
},
{
name: "syncer-is-not-priority",
givenUids: map[string]UIDEntry{
"onlyPriorityElement": {
UID: "123",
Expires: time.Now().Add((90 * 24 * time.Hour)),
},
"syncer": {
UID: "456",
Expires: time.Now().Add((90 * 24 * time.Hour)),
},
},
givenEjector: &PriorityBidderEjector{
PriorityGroups: [][]string{
{"onlyPriorityElement"},
},
syncersByBidder: map[string]Syncer{
"onlyPriorityElement": fakeSyncer{
key: "onlyPriorityElement",
},
},
IsSyncerPriority: false,
},
expectedError: errors.New("syncer key is not a priority, and there are only priority elements left"),
},
}

for _, test := range testCases {
Expand Down

0 comments on commit bc8c72a

Please sign in to comment.