Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
0f955e9
Remove invalid user EIDs and UIDs from bid request
Pubmatic-Supriya-Patil Aug 28, 2024
9352604
Merge branch 'master' of github.com:Pubmatic-Supriya-Patil/prebid-ser…
Pubmatic-Supriya-Patil Dec 2, 2024
541cbed
Merge branch 'master' of github.com:Pubmatic-Supriya-Patil/prebid-ser…
Pubmatic-Supriya-Patil Jan 13, 2025
22e6b21
Removed redundant check for uid.id validation
Pubmatic-Supriya-Patil Jan 14, 2025
db31c94
Merge branch 'master' of github.com:Pubmatic-Supriya-Patil/prebid-ser…
Pubmatic-Supriya-Patil Jan 16, 2025
0f45f16
Merge branch 'master' of github.com:Pubmatic-Supriya-Patil/prebid-ser…
Pubmatic-Supriya-Patil Feb 4, 2025
5514eae
Refactor EID validation to issue warnings for missing source field in…
Pubmatic-Supriya-Patil Feb 4, 2025
74d9c26
Remove validation for empty UIDs in user EIDs
Pubmatic-Supriya-Patil Feb 28, 2025
5d56a61
Merge branch 'prebid:master' into Fix_3859
Pubmatic-Supriya-Patil Feb 28, 2025
5c45e53
Merge branch 'prebid:master' into Fix_3859
Pubmatic-Supriya-Patil Mar 4, 2025
4dcd6c9
Update EID validation to remove entries with empty UIDs and add new t…
Pubmatic-Supriya-Patil Mar 7, 2025
675bd31
Merge branch 'Fix_3859' of github.com:Pubmatic-Supriya-Patil/prebid-s…
Pubmatic-Supriya-Patil Mar 7, 2025
f6eea3c
Move user-eids-uids-empty.json to valid-whole folder
Pubmatic-Supriya-Patil Mar 19, 2025
ff59f36
Merge branch 'prebid:master' into Fix_3859
Pubmatic-Supriya-Patil Mar 19, 2025
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
50 changes: 48 additions & 2 deletions endpoints/openrtb2/auction.go
Original file line number Diff line number Diff line change
Expand Up @@ -1296,8 +1296,14 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases
// Check Universal User ID
eids := userExt.GetEid()
if eids != nil {
eidsValue := *eids
for eidIndex, eid := range eidsValue {

Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick; Please remove the leading empty line.

validEids, eidErrors := validateEIDs(*eids)

if len(eidErrors) > 0 {
errL = append(errL, eidErrors...)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Likely fine to keep this logic here for now. We want to separate validation from fixing in the future. We can refactor this new logic along with the rest later. Thoughts @bsardo?


for eidIndex, eid := range validEids {
if eid.Source == "" {
return append(errL, fmt.Errorf("request.user.ext.eids[%d] missing required field: \"source\"", eidIndex))
}
Expand All @@ -1317,6 +1323,46 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases
return errL
}

func validateEIDs(eids []openrtb2.EID) ([]openrtb2.EID, []error) {
var errorsList []error
validEIDs := make([]openrtb2.EID, 0, len(eids))

for _, eid := range eids {
validUIDs, uidErrors := validateUIDs(eid.UIDs)
errorsList = append(errorsList, uidErrors...)

if len(validUIDs) > 0 {
eid.UIDs = validUIDs
validEIDs = append(validEIDs, eid)
} else {
errorsList = append(errorsList, &errortypes.Warning{
Message: fmt.Sprintf("Removed EID with empty UIDs (source: %s)", eid.Source),
Copy link
Contributor

Choose a reason for hiding this comment

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

Please keep with the established error message format. Perhaps something like:

request.user.ext.eids[0] (source: %s) contains only empty uids and is removed from the request

WarningCode: errortypes.InvalidUserEIDsWarningCode,
})
}
}

return validEIDs, errorsList
}

func validateUIDs(uids []openrtb2.UID) ([]openrtb2.UID, []error) {
var validUIDs []openrtb2.UID
var uidErrors []error

for _, uid := range uids {
if uid.ID != "" {
validUIDs = append(validUIDs, uid)
} else {
uidErrors = append(uidErrors, &errortypes.Warning{
Message: "Removed UID due to empty ID",
WarningCode: errortypes.InvalidUserUIDsWarningCode,
})
}
}

return validUIDs, uidErrors
}

func validateRegs(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) []error {
var errL []error

Expand Down
176 changes: 176 additions & 0 deletions endpoints/openrtb2/auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5922,3 +5922,179 @@ func sortUserData(user *openrtb2.User) {
}
}
}
func TestValidateEIDs(t *testing.T) {
testCases := []struct {
name string
input []openrtb2.EID
expected []openrtb2.EID
numErrors int
expectedErrorMessages []string
}{
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add the following test cases:

  • eid-nil
  • eid-uid-nil
  • source-missing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added test cases for given scenarios

name: "Valid EID with non-empty UID",
Copy link
Contributor

Choose a reason for hiding this comment

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

Go test names cannot contain spaces so they are replaced with a dash character. This makes it hard to locate the failing test based on its name. Recommend using simpler test names like:

  • one-eid-one-uid-valid
  • one-eid-one-uid-empty
  • many-mixed
  • one-eid-many-uid-empty

The parent test name is within scope so it's easy to locate in source. Please apply this guidance to other tests added in this PR.

input: []openrtb2.EID{
{Source: "src1", UIDs: []openrtb2.UID{{ID: "id1"}}},
},
expected: []openrtb2.EID{
{Source: "src1", UIDs: []openrtb2.UID{{ID: "id1"}}},
},
numErrors: 0,
expectedErrorMessages: nil,
},
{
name: "EID with empty UID",
input: []openrtb2.EID{
{Source: "src2", UIDs: []openrtb2.UID{{ID: ""}}},
},
expected: []openrtb2.EID{},
numErrors: 2,
expectedErrorMessages: []string{
"Removed UID due to empty ID",
"Removed EID with empty UIDs (source: src2)",
},
},
{
name: "Multiple EIDs with some empty UIDs",
input: []openrtb2.EID{
{Source: "src3", UIDs: []openrtb2.UID{{ID: "ID1"}, {ID: "ID2"}}},
{Source: "src4", UIDs: []openrtb2.UID{{ID: ""}, {ID: "ID1"}}},
{Source: "src5", UIDs: []openrtb2.UID{{ID: ""}, {ID: ""}}},
},
expected: []openrtb2.EID{
{Source: "src3", UIDs: []openrtb2.UID{{ID: "ID1"}, {ID: "ID2"}}},
{Source: "src4", UIDs: []openrtb2.UID{{ID: "ID1"}}},
},
numErrors: 4,
expectedErrorMessages: []string{
"Removed UID due to empty ID",
"Removed UID due to empty ID",
"Removed UID due to empty ID",
"Removed EID with empty UIDs (source: src5)",
},
},
{
name: "All UIDs are empty",
input: []openrtb2.EID{
{Source: "src6", UIDs: []openrtb2.UID{{ID: ""}, {ID: ""}}},
},
expected: []openrtb2.EID{},
numErrors: 3,
expectedErrorMessages: []string{
"Removed UID due to empty ID",
"Removed UID due to empty ID",
"Removed EID with empty UIDs (source: src6)",
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
validEIDs, errorsList := validateEIDs(tc.input)

if len(validEIDs) != len(tc.expected) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use testify assert statements where possible. This can be written as follows which will compare the contents instead of just the array lengths, yielding more concrete tests.

assert.ElementsMatch(e, tc.expected, validEIDs)

t.Errorf("Expected %d valid EIDs, but got %d", len(tc.expected), len(validEIDs))
}

if len(errorsList) != tc.numErrors {
t.Errorf("Expected %d errors, but got %d", tc.numErrors, len(errorsList))
}

// Assert error messages
if tc.numErrors > 0 {
var errorMessages []string
for _, err := range errorsList {
if warning, ok := err.(*errortypes.Warning); ok {
errorMessages = append(errorMessages, warning.Message)
}
}

for i, expectedMsg := range tc.expectedErrorMessages {
if i >= len(errorMessages) {
t.Errorf("Expected error message %q but got none", expectedMsg)
} else if expectedMsg != errorMessages[i] {
t.Errorf("Expected error message %q but got %q", expectedMsg, errorMessages[i])
}
}
}
})
}
}

func TestValidateUIDs(t *testing.T) {
testCases := []struct {
name string
input []openrtb2.UID
expectedValidUIDs []openrtb2.UID
expectedErrors []error
}{
{
name: "All valid UIDs",
input: []openrtb2.UID{
{ID: "id1"},
{ID: "id2"},
},
expectedValidUIDs: []openrtb2.UID{
{ID: "id1"},
{ID: "id2"},
},
expectedErrors: nil,
},
{
name: "All empty UIDs",
input: []openrtb2.UID{
{ID: ""},
{ID: ""},
},
expectedValidUIDs: nil,
expectedErrors: []error{
&errortypes.Warning{
Message: "Removed UID due to empty ID",
WarningCode: errortypes.InvalidUserUIDsWarningCode,
},
&errortypes.Warning{
Message: "Removed UID due to empty ID",
WarningCode: errortypes.InvalidUserUIDsWarningCode,
},
},
},
{
name: "Mixed valid and empty UIDs",
input: []openrtb2.UID{
{ID: "id1"},
{ID: ""},
{ID: "id2"},
{ID: ""},
},
expectedValidUIDs: []openrtb2.UID{
{ID: "id1"},
{ID: "id2"},
},
expectedErrors: []error{
&errortypes.Warning{
Message: "Removed UID due to empty ID",
WarningCode: errortypes.InvalidUserUIDsWarningCode,
},
&errortypes.Warning{
Message: "Removed UID due to empty ID",
WarningCode: errortypes.InvalidUserUIDsWarningCode,
},
},
},
{
name: "No UIDs",
input: []openrtb2.UID{},
expectedValidUIDs: nil,
expectedErrors: nil,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a test case for a nil input.


for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
validUIDs, errorsList := validateUIDs(tc.input)

assert.ElementsMatch(t, tc.expectedValidUIDs, validUIDs, "Valid UIDs mismatch")

assert.ElementsMatch(t, tc.expectedErrors, errorsList, "Errors mismatch")
})
}
}

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions errortypes/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const (
InvalidBidResponseDSAWarningCode
SecCookieDeprecationLenWarningCode
SecBrowsingTopicsWarningCode
InvalidUserEIDsWarningCode
InvalidUserUIDsWarningCode
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these new warning codes match with PBS-Java? We try to keep in sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you please help me to get those error codes. Do we have any document or PR to check new warning codes match with PBS-Java.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per prebid-server-java/pull/3465, I understand that the same 999 warning code is being used when removing eids arrays. In the Prebid Server Go repository, 999 corresponds to UnknownErrorCode in the error codes reference. Are we intending to use UnknownErrorCode here as well?

In this PR, I introduced InvalidUserEIDsWarningCode (10013) and InvalidUserUIDsWarningCode (10014). If we are okay with a generic error code, we could use UnknownErrorCode (999). However, please confirm whether we want separate error codes for InvalidUserEIDs and InvalidUserUIDs, or if using 999 would suffice.

Kindly provide your input on this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

As discussed offline, it is ok to have these error codes. No change needed.

)

// Coder provides an error or warning code with severity.
Expand Down
Loading