From 72b160b4f3756720a229925e9c9200597d4209f4 Mon Sep 17 00:00:00 2001 From: AlexBVolcy Date: Thu, 12 Oct 2023 09:20:57 -0700 Subject: [PATCH] Update case insensitivity + tests --- endpoints/openrtb2/auction.go | 7 ++ ...actors-case-invalid-same-bidder-names.json | 81 ++++++++++++++++ ...ors-case-insensitive-different-casing.json | 97 +++++++++++++++++++ ... => bid-adj-factors-case-insensitive.json} | 0 exchange/bidder.go | 4 +- exchange/bidder_test.go | 14 +-- exchange/utils.go | 9 +- exchange/utils_test.go | 5 + 8 files changed, 206 insertions(+), 11 deletions(-) create mode 100644 endpoints/openrtb2/sample-requests/invalid-whole/bid-adj-factors-case-invalid-same-bidder-names.json create mode 100644 endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive-different-casing.json rename endpoints/openrtb2/sample-requests/valid-whole/exemplary/{bidder-adjustment-factors-case-insensitive.json => bid-adj-factors-case-insensitive.json} (100%) diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 4fce4c15786..670a2a8c669 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -961,6 +961,7 @@ func validateAndFillSourceTID(req *openrtb_ext.RequestWrapper, generateRequestID } func (deps *endpointDeps) validateBidAdjustmentFactors(adjustmentFactors map[string]float64, aliases map[string]string) error { + uniqueBidders := make(map[string]struct{}) for bidderToAdjust, adjustmentFactor := range adjustmentFactors { if adjustmentFactor <= 0 { return fmt.Errorf("request.ext.prebid.bidadjustmentfactors.%s must be a positive number. Got %f", bidderToAdjust, adjustmentFactor) @@ -972,6 +973,12 @@ func (deps *endpointDeps) validateBidAdjustmentFactors(adjustmentFactors map[str bidderName = normalizedCoreBidder.String() } + if _, exists := uniqueBidders[bidderName]; exists { + return fmt.Errorf("cannot have multiple bidders that differ only in case style") + } else { + uniqueBidders[bidderName] = struct{}{} + } + if _, isBidder := deps.bidderMap[bidderName]; !isBidder { if _, isAlias := aliases[bidderToAdjust]; !isAlias { return fmt.Errorf("request.ext.prebid.bidadjustmentfactors.%s is not a known bidder or alias", bidderToAdjust) diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/bid-adj-factors-case-invalid-same-bidder-names.json b/endpoints/openrtb2/sample-requests/invalid-whole/bid-adj-factors-case-invalid-same-bidder-names.json new file mode 100644 index 00000000000..d484f129ba3 --- /dev/null +++ b/endpoints/openrtb2/sample-requests/invalid-whole/bid-adj-factors-case-invalid-same-bidder-names.json @@ -0,0 +1,81 @@ +{ + "description": "This demonstrates a request with bidadjustmentfactors that have multiple of the same bidder is invalid request", + "config": { + "mockBidders": [ + { + "bidderName": "appnexus", + "currency": "USD", + "price": 1.00 + } + ] + }, + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "ext": { + "consent": "gdpr-consent-string" + } + }, + "regs": { + "ext": { + "gdpr": 1, + "us_privacy": "1NYN" + } + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "Appnexus": { + "placementId": 12883451 + } + } + } + ], + "tmax": 500, + "ext": { + "prebid": { + "bidadjustmentfactors": { + "APPNEXUS": 1.01, + "Appnexus": 2.00 + }, + "cache": { + "bids": {} + }, + "channel": { + "name": "video", + "version": "1.0" + }, + "targeting": { + "includewinners": false, + "pricegranularity": { + "precision": 2, + "ranges": [ + { + "max": 20, + "increment": 0.10 + } + ] + } + } + } + } + }, + "expectedReturnCode": 400, + "expectedErrorMessage": "Invalid request: cannot have multiple bidders that differ only in case style" +} \ No newline at end of file diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive-different-casing.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive-different-casing.json new file mode 100644 index 00000000000..a231af657cd --- /dev/null +++ b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive-different-casing.json @@ -0,0 +1,97 @@ +{ + "description": "This demonstrates bid adjustment factors with bidder names that have different casing in imp vs. in bidadjustmentfactors", + "config": { + "mockBidders": [ + { + "bidderName": "appnexus", + "currency": "USD", + "price": 1.00 + } + ] + }, + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "ext": { + "consent": "gdpr-consent-string" + } + }, + "regs": { + "ext": { + "gdpr": 1, + "us_privacy": "1NYN" + } + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "Appnexus": { + "placementId": 12883451 + } + } + } + ], + "tmax": 500, + "ext": { + "prebid": { + "bidadjustmentfactors": { + "APPNEXUS": 1.01 + }, + "cache": { + "bids": {} + }, + "channel": { + "name": "video", + "version": "1.0" + }, + "targeting": { + "includewinners": false, + "pricegranularity": { + "precision": 2, + "ranges": [ + { + "max": 20, + "increment": 0.10 + } + ] + } + } + } + } + }, + "expectedBidResponse": { + "id": "some-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "appnexus-bid", + "impid": "some-impression-id", + "price": 1.01 + } + ], + "seat": "Appnexus" + } + ], + "bidid": "test bid id", + "cur": "USD", + "nbr": 0 + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/bidder-adjustment-factors-case-insensitive.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive.json similarity index 100% rename from endpoints/openrtb2/sample-requests/valid-whole/exemplary/bidder-adjustment-factors-case-insensitive.json rename to endpoints/openrtb2/sample-requests/valid-whole/exemplary/bid-adj-factors-case-insensitive.json diff --git a/exchange/bidder.go b/exchange/bidder.go index dfdb7cdf85f..40135787b25 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -348,9 +348,9 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, bidderRequest Bidde } adjustmentFactor := 1.0 - if givenAdjustment, ok := bidRequestOptions.bidAdjustments[bidderName.String()]; ok { + if givenAdjustment, ok := bidRequestOptions.bidAdjustments[(strings.ToLower(bidderName.String()))]; ok { adjustmentFactor = givenAdjustment - } else if givenAdjustment, ok := bidRequestOptions.bidAdjustments[bidderRequest.BidderName.String()]; ok { + } else if givenAdjustment, ok := bidRequestOptions.bidAdjustments[(strings.ToLower(bidderRequest.BidderName.String()))]; ok { adjustmentFactor = givenAdjustment } diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index 65f6b795247..09c811ba9c6 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -2672,7 +2672,7 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { }, BidType: openrtb_ext.BidTypeBanner, DealPriority: 4, - Seat: "pubmatic", + Seat: "PUBMATIC", }, { Bid: &openrtb2.Bid{ @@ -2699,7 +2699,7 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { BidType: openrtb_ext.BidTypeVideo, OriginalBidCPM: 7, OriginalBidCur: "USD", - BidMeta: &openrtb_ext.ExtBidPrebidMeta{AdapterCode: string(openrtb_ext.BidderPubmatic)}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{AdapterCode: "PUBMATIC"}, }}, Seat: "groupm", Currency: "USD", @@ -2715,9 +2715,9 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { BidType: openrtb_ext.BidTypeBanner, OriginalBidCur: "USD", OriginalBidCPM: 3, - BidMeta: &openrtb_ext.ExtBidPrebidMeta{AdapterCode: string(openrtb_ext.BidderPubmatic)}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{AdapterCode: "PUBMATIC"}, }}, - Seat: string(openrtb_ext.BidderPubmatic), + Seat: "PUBMATIC", Currency: "USD", }, } @@ -2727,10 +2727,10 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, - BidderName: openrtb_ext.BidderPubmatic, + BidderName: "PUBMATIC", } bidAdjustments := map[string]float64{ - string(openrtb_ext.BidderPubmatic): 2, + string(openrtb_ext.BidderPubmatic): 2, // All lowercase value in bid adjustments to simulate it being case insensitive "groupm": 3, } @@ -2745,7 +2745,7 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { openrtb_ext.ExtAlternateBidderCodes{ Enabled: true, Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{ - string(openrtb_ext.BidderPubmatic): { + "PUBMATIC": { Enabled: true, AllowedBidderCodes: []string{"groupm"}, }, diff --git a/exchange/utils.go b/exchange/utils.go index 0a38e487632..6e8985dce2e 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "math/rand" + "strings" "github.com/buger/jsonparser" "github.com/prebid/go-gdpr/vendorconsent" @@ -892,8 +893,12 @@ func parseRequestDebugValues(test int8, requestExtPrebid *openrtb_ext.ExtRequest } func getExtBidAdjustmentFactors(requestExtPrebid *openrtb_ext.ExtRequestPrebid) map[string]float64 { - if requestExtPrebid != nil { - return requestExtPrebid.BidAdjustmentFactors + if requestExtPrebid != nil && requestExtPrebid.BidAdjustmentFactors != nil { + caseInsensitiveMap := make(map[string]float64, len(requestExtPrebid.BidAdjustmentFactors)) + for bidder, bidAdjFactor := range requestExtPrebid.BidAdjustmentFactors { + caseInsensitiveMap[strings.ToLower(bidder)] = bidAdjFactor + } + return caseInsensitiveMap } return nil } diff --git a/exchange/utils_test.go b/exchange/utils_test.go index ee6dad1ad96..9f0abb6e242 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -1834,6 +1834,11 @@ func TestGetExtBidAdjustmentFactors(t *testing.T) { requestExtPrebid: &openrtb_ext.ExtRequestPrebid{BidAdjustmentFactors: map[string]float64{"bid-factor": 1.0}}, outBidAdjustmentFactors: map[string]float64{"bid-factor": 1.0}, }, + { + desc: "BidAdjustmentFactors contains uppercase bidders, expect case insensitve map returned", + requestExtPrebid: &openrtb_ext.ExtRequestPrebid{BidAdjustmentFactors: map[string]float64{"Bidder": 1.0, "APPNEXUS": 2.0}}, + outBidAdjustmentFactors: map[string]float64{"bidder": 1.0, "appnexus": 2.0}, + }, } for _, test := range testCases { actualBidAdjustmentFactors := getExtBidAdjustmentFactors(test.requestExtPrebid)