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

Remove invalid user EIDs and UIDs from bid request #3891

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

Pubmatic-Supriya-Patil
Copy link
Contributor

This PR solves issue #3859

@Pubmatic-Supriya-Patil
Copy link
Contributor Author

Hi @bsardo @bretg
Please review this PR and let me know if any changes are required.

@bsardo bsardo self-assigned this Oct 21, 2024
@@ -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.

@@ -1,42 +0,0 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of removing these tests cases, please modify them to prove the new behavior.

@@ -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.


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?

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

expectedErrorMessages []string
}{
{
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.

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)

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.

@bsardo
Copy link
Collaborator

bsardo commented Nov 4, 2024

Hi @Pubmatic-Supriya-Patil, can you please merge with master (no rebase) and resolve conflicts? Thanks!

@SyntaxNode
Copy link
Contributor

Thank you for contributing this feature Please address the comments and we will re-review.

@Pubmatic-Supriya-Patil
Copy link
Contributor Author

Hi @Pubmatic-Supriya-Patil, can you please merge with master (no rebase) and resolve conflicts? Thanks!

HI @bsardo I have updated branch and addressed review comments.

Comment on lines 1296 to 1299
for uidIndex, uid := range eid.UIDs {
if uid.ID == "" {
return append(errL, fmt.Errorf("request.user.eids[%d].uids[%d] missing required field: \"id\"", eidIndex, uidIndex))
}
Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 Dec 10, 2024

Choose a reason for hiding this comment

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

At this time we will not have empty eid.ID, correct? there is a check for this already in line 1334.

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 Dec 10, 2024

Choose a reason for hiding this comment

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

Also do we need to set "clean" EIDs back to req.User.EIDs?
Something like req.User.EIDs = validEids after the for loop?

Please correct me if I'm wrong. We don't want to fail the entire request if there is at least one invalid EID, correct? Or do we want to drop invalid ones and continue the execution?
If we want to continue the execution - please add this fix and json tests where we validate "clean" user.EIDs and error messages.

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 we remove if len(eid.UIDs) == 0 { validation also from validateUser function. This is also not possible because validateEids wil return error for emtpy uids. Please provide your suggestions @VeronikaSolovei9

Copy link
Contributor

Choose a reason for hiding this comment

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

No no, I didn't ask to delete if len(eid.UIDs) == 0 { - it is needed here. I only asked about if we want to add valid aids to the request. And you fixed this by adding this line: req.User.EIDs = validEids

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay. Thanks. Please review PR

@ShriprasadM
Copy link
Contributor

@Pubmatic-Supriya-Patil : Please respond to this comments.

@bsardo
Copy link
Collaborator

bsardo commented Jan 15, 2025

@Pubmatic-Supriya-Patil can you please merge with master? That should resolve the failing validate-merge check.

Comment on lines 1287 to 1293
for eidIndex, eid := range validEids {
if eid.Source == "" {
return append(errL, fmt.Errorf("request.user.eids[%d] missing required field: \"source\"", eidIndex))
}

for uidIndex, uid := range eid.UIDs {
if uid.ID == "" {
return append(errL, fmt.Errorf("request.user.eids[%d].uids[%d] missing required field: \"id\"", eidIndex, uidIndex))
if len(eid.UIDs) == 0 {
return append(errL, fmt.Errorf("request.user.eids[%d].uids must contain at least one element or be undefined", eidIndex))
Copy link
Contributor

Choose a reason for hiding this comment

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

This code fails the request if eids look like this:

"eids": [
			{
				"source": "uidapi.com",
				"uids": [
					{
						"id": ""
					},
					{
						"id": "id111111"
					}
				]
			},
			{
				"source": "liveramp.com",
				"uids": [
					{
						"id": "id22222"
					}
				]
			},
			{
				"source": "", <<< this is the problem
				"uids": [
					{
						"id": "123"
					},
					{
						"id": "1234"
					}
				]
			}
		]

All eids are added to the valid list, because they have at least one valid id. The last eid doesn't have a source and instead of removing this eid from the list of valid aids - we return fatal error and fail the request with unexpected message:

Invalid request: request.user.eids[0].uids[0] contains empty ids and is removed from the request
Invalid request: request.user.eids[2] missing required field: "source"

Possible fix: move these 2 checks to the validateEIDs function after validateUIDs.
Add message to the error list and don't add this aid to the list of valid eids.

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 my understanding, the logic for removing invalid IDs is specific to eids. We have retained the existing logic for checking the source. However, it is unclear whether we need to check for an empty source and remove that entry while allowing other valid eids. @VeronikaSolovei9, could you please confirm this scenario and clarify the expected behavior in this case?

Copy link
Contributor

Choose a reason for hiding this comment

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

I will ask team about the expected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

My take is that EID.source is required. IMO, makes sense to remove empty sources.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The team discussed offline. We're in agreement that if EID.source is invalid we should simply remove the corresponding EID without failing the request. We should also add a warning message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the update. I’ll incorporate the required changes.

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 left a comment

Choose a reason for hiding this comment

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

Thank you for the changes, approved!

Comment on lines 1287 to 1291
for eidIndex, eid := range validEids {
if len(eid.UIDs) == 0 {
return append(errL, fmt.Errorf("request.user.eids[%d].uids must contain at least one element or be undefined", eidIndex))
}
}
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, we can remove this error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

@@ -35,6 +35,8 @@ const (
InvalidBidResponseDSAWarningCode
SecCookieDeprecationLenWarningCode
SecBrowsingTopicsWarningCode
InvalidUserEIDsWarningCode
InvalidUserUIDsWarningCode
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.

@@ -35,6 +35,6 @@
}]
}
},
"expectedReturnCode": 400,
"expectedErrorMessage": "Invalid request: request.user.eids[0].uids[0] missing required field: \"id\"\n"
"expectedReturnCode": 200,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we edit this test on lines 31-336 so that there are no uid objects:

"user": {
    "eids": [{
        "source": "source1",
        "uids": []
    }]
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add a new JSON test user-eids-empty-uids-removed.json that is similar to the example in the corresponding issue?
[{"source":"a","uids":[{"id":""}, {"id":"id-a"}]}, {"source":"b","uids":[{"id":"id-b"}]}, {"source":"c","uids":[{"id":""},{"id":""}]}]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

The JSON tests here now return 200s so they should be moved out of the invalid-whole directory to some other valid request directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to valid-whole

"expectedReturnCode": 400,
"expectedErrorMessage": "Invalid request: request.user.eids[0] missing required field: \"source\"\n"
"expectedReturnCode": 200,
"expectedErrorMessage": "request.user.eids[0] missing required field: source"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since all of these JSON test errors are now reported as warnings and since the endpoint JSON test framework does not allow both expectedBidResponse and expectedErrorMessage in a given JSON test, it would be better to use the following approach:

  • Add expectedBidResponse object
  • Specify the expected warnings in the expectedBidResponse object under ext.warnings

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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

Comment on lines 6173 to 6174
assert.ElementsMatch(t, tc.expectedValidUIDs, validUIDs, "Valid UIDs mismatch")
assert.ElementsMatch(t, tc.expectedErrors, errorsList, "Errors mismatch")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: you can delete the last parameter in these assert statements. t.Run will give the appropriate context should one of these assertions fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed last parameter

if eid.Source == "" {
return append(errL, fmt.Errorf("request.user.eids[%d] missing required field: \"source\"", eidIndex))
errorsList = append(errorsList, &errortypes.Warning{
Message: fmt.Sprintf("request.user.eids[%d] missing required field: source", eidIndex),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: can we change the error message a bit so that all of the messages in this function have similar wording?
request.user.eids[%d] removed due to missing source

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

validEIDs = append(validEIDs, eid)
} else {
errorsList = append(errorsList, &errortypes.Warning{
Message: fmt.Sprintf("request.user.eids[%d] (source: %s) contains only empty uids and is removed from the request", eidIndex, eid.Source),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: can we change the error message a bit so that all of the messages in this function have similar wording and so it is a bit more concise?
request.user.eids[%d] (%s) removed due to empty uids

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

validUIDs = append(validUIDs, uid)
} else {
uidErrors = append(uidErrors, &errortypes.Warning{
Message: fmt.Sprintf("request.user.eids[%d].uids[%d] contains empty ids and is removed from the request", eidIndex, uidIndex),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: can we change the error message a bit so that all of the messages in this function have similar wording and so it is a bit more concise?
request.user.eids[%d].uids[%d] removed due to empty ids

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

expectedEids []openrtb2.EID
}{
{
description: "Valid user with Geo accuracy",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: use name instead of description and replace all test case name spaces with underscores

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants