From 16428bba5d29ea66cf54a7fca2e011a8b5fbc38c Mon Sep 17 00:00:00 2001 From: Mansi Nahar Date: Thu, 10 Dec 2020 10:01:02 -0500 Subject: [PATCH] Add a BidderRequest struct to hold bidder specific request info (#1611) --- exchange/exchange.go | 91 +++++++++++++---------- exchange/exchange_test.go | 34 ++++++--- exchange/utils.go | 97 ++++++++++++------------- exchange/utils_test.go | 149 +++++++++++++++++++++++--------------- 4 files changed, 215 insertions(+), 156 deletions(-) diff --git a/exchange/exchange.go b/exchange/exchange.go index 6d5d73d8d39..83fbb0163a4 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -95,6 +95,8 @@ func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid } } +// AuctionRequest holds the bid request for the auction +// and all other information needed to process that request type AuctionRequest struct { BidRequest *openrtb.BidRequest Account config.Account @@ -107,6 +109,15 @@ type AuctionRequest struct { LegacyLabels pbsmetrics.Labels } +// BidderRequest holds the bidder specific request and all other +// information needed to process that bidder request. +type BidderRequest struct { + BidRequest *openrtb.BidRequest + BidderName openrtb_ext.BidderName + BidderCoreName openrtb_ext.BidderName + BidderLabels pbsmetrics.AdapterLabels +} + func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *DebugLog) (*openrtb.BidResponse, error) { var err error requestExt, err := extractBidRequestExt(r.BidRequest) @@ -133,13 +144,12 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog * usersyncIfAmbiguous := e.parseUsersyncIfAmbiguous(r.BidRequest) // Slice of BidRequests, each a copy of the original cleaned to only contain bidder data for the named bidder - blabels := make(map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels) - cleanRequests, aliases, privacyLabels, errs := cleanOpenRTBRequests(ctx, r.BidRequest, requestExt, r.UserSyncs, blabels, r.LegacyLabels, e.gDPR, usersyncIfAmbiguous, e.privacyConfig, &r.Account) + bidderRequests, privacyLabels, errs := cleanOpenRTBRequests(ctx, r, requestExt, e.gDPR, usersyncIfAmbiguous, e.privacyConfig) e.me.RecordRequestPrivacy(privacyLabels) // List of bidders we have requests for. - liveAdapters := listBiddersWithRequests(cleanRequests) + liveAdapters := listBiddersWithRequests(bidderRequests) // If we need to cache bids, then it will take some time to call prebid cache. // We should reduce the amount of time the bidders have, to compensate. @@ -149,7 +159,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog * // Get currency rates conversions for the auction conversions := e.currencyConverter.Rates() - adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, cleanRequests, aliases, bidAdjustmentFactors, blabels, conversions) + adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions) var auc *auction var cacheErrs []error @@ -325,37 +335,42 @@ func (e *exchange) makeAuctionContext(ctx context.Context, needsCache bool) (auc } // This piece sends all the requests to the bidder adapters and gathers the results. -func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext.BidderName]*openrtb.BidRequest, aliases map[string]string, bidAdjustments map[string]float64, blabels map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels, conversions currencies.Conversions) (map[openrtb_ext.BidderName]*pbsOrtbSeatBid, map[openrtb_ext.BidderName]*seatResponseExtra, bool) { +func (e *exchange) getAllBids( + ctx context.Context, + bidderRequests []BidderRequest, + bidAdjustments map[string]float64, + conversions currencies.Conversions) ( + map[openrtb_ext.BidderName]*pbsOrtbSeatBid, + map[openrtb_ext.BidderName]*seatResponseExtra, bool) { // Set up pointers to the bid results - adapterBids := make(map[openrtb_ext.BidderName]*pbsOrtbSeatBid, len(cleanRequests)) - adapterExtra := make(map[openrtb_ext.BidderName]*seatResponseExtra, len(cleanRequests)) - chBids := make(chan *bidResponseWrapper, len(cleanRequests)) + adapterBids := make(map[openrtb_ext.BidderName]*pbsOrtbSeatBid, len(bidderRequests)) + adapterExtra := make(map[openrtb_ext.BidderName]*seatResponseExtra, len(bidderRequests)) + chBids := make(chan *bidResponseWrapper, len(bidderRequests)) bidsFound := false - for bidderName, req := range cleanRequests { + for _, bidder := range bidderRequests { // Here we actually call the adapters and collect the bids. - coreBidder := resolveBidder(string(bidderName), aliases) - bidderRunner := e.recoverSafely(cleanRequests, func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) { + bidderRunner := e.recoverSafely(bidderRequests, func(bidderRequest BidderRequest, conversions currencies.Conversions) { // Passing in aName so a doesn't change out from under the go routine - if bidlabels.Adapter == "" { - glog.Errorf("Exchange: bidlables for %s (%s) missing adapter string", aName, coreBidder) - bidlabels.Adapter = coreBidder + if bidderRequest.BidderLabels.Adapter == "" { + glog.Errorf("Exchange: bidlables for %s (%s) missing adapter string", bidderRequest.BidderName, bidderRequest.BidderCoreName) + bidderRequest.BidderLabels.Adapter = bidderRequest.BidderCoreName } brw := new(bidResponseWrapper) - brw.bidder = aName + brw.bidder = bidderRequest.BidderName // Defer basic metrics to insure we capture them after all the values have been set defer func() { - e.me.RecordAdapterRequest(*bidlabels) + e.me.RecordAdapterRequest(bidderRequest.BidderLabels) }() start := time.Now() adjustmentFactor := 1.0 - if givenAdjustment, ok := bidAdjustments[string(aName)]; ok { + if givenAdjustment, ok := bidAdjustments[string(bidderRequest.BidderName)]; ok { adjustmentFactor = givenAdjustment } var reqInfo adapters.ExtraRequestInfo - reqInfo.PbsEntryPoint = bidlabels.RType - bids, err := e.adapterMap[coreBidder].requestBid(ctx, request, aName, adjustmentFactor, conversions, &reqInfo) + reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType + bids, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest.BidRequest, bidderRequest.BidderName, adjustmentFactor, conversions, &reqInfo) // Add in time reporting elapsed := time.Since(start) @@ -368,26 +383,26 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext } // Timing statistics - e.me.RecordAdapterTime(*bidlabels, time.Since(start)) + e.me.RecordAdapterTime(bidderRequest.BidderLabels, time.Since(start)) serr := errsToBidderErrors(err) - bidlabels.AdapterBids = bidsToMetric(brw.adapterBids) - bidlabels.AdapterErrors = errorsToMetric(err) + bidderRequest.BidderLabels.AdapterBids = bidsToMetric(brw.adapterBids) + bidderRequest.BidderLabels.AdapterErrors = errorsToMetric(err) // Append any bid validation errors to the error list ae.Errors = serr brw.adapterExtra = ae if bids != nil { for _, bid := range bids.bids { var cpm = float64(bid.bid.Price * 1000) - e.me.RecordAdapterPrice(*bidlabels, cpm) - e.me.RecordAdapterBidReceived(*bidlabels, bid.bidType, bid.bid.AdM != "") + e.me.RecordAdapterPrice(bidderRequest.BidderLabels, cpm) + e.me.RecordAdapterBidReceived(bidderRequest.BidderLabels, bid.bidType, bid.bid.AdM != "") } } chBids <- brw }, chBids) - go bidderRunner(bidderName, coreBidder, req, blabels[coreBidder], conversions) + go bidderRunner(bidder, conversions) } // Wait for the bidders to do their thing - for i := 0; i < len(cleanRequests); i++ { + for i := 0; i < len(bidderRequests); i++ { brw := <-chBids //if bidder returned no bids back - remove bidder from further processing @@ -405,15 +420,17 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext return adapterBids, adapterExtra, bidsFound } -func (e *exchange) recoverSafely(cleanRequests map[openrtb_ext.BidderName]*openrtb.BidRequest, inner func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions), chBids chan *bidResponseWrapper) func(openrtb_ext.BidderName, openrtb_ext.BidderName, *openrtb.BidRequest, *pbsmetrics.AdapterLabels, currencies.Conversions) { - return func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) { +func (e *exchange) recoverSafely(bidderRequests []BidderRequest, + inner func(BidderRequest, currencies.Conversions), + chBids chan *bidResponseWrapper) func(BidderRequest, currencies.Conversions) { + return func(bidderRequest BidderRequest, conversions currencies.Conversions) { defer func() { if r := recover(); r != nil { allBidders := "" sb := strings.Builder{} - for k := range cleanRequests { - sb.WriteString(string(k)) + for _, bidder := range bidderRequests { + sb.WriteString(bidder.BidderName.String()) sb.WriteString(",") } if sb.Len() > 0 { @@ -422,15 +439,15 @@ func (e *exchange) recoverSafely(cleanRequests map[openrtb_ext.BidderName]*openr glog.Errorf("OpenRTB auction recovered panic from Bidder %s: %v. "+ "Account id: %s, All Bidders: %s, Stack trace is: %v", - coreBidder, r, bidlabels.PubID, allBidders, string(debug.Stack())) - e.me.RecordAdapterPanic(*bidlabels) + bidderRequest.BidderCoreName, r, bidderRequest.BidderLabels.PubID, allBidders, string(debug.Stack())) + e.me.RecordAdapterPanic(bidderRequest.BidderLabels) // Let the master request know that there is no data here brw := new(bidResponseWrapper) brw.adapterExtra = new(seatResponseExtra) chBids <- brw } }() - inner(aName, coreBidder, request, bidlabels, conversions) + inner(bidderRequest, conversions) } } @@ -870,11 +887,11 @@ func buildCacheURL(cache prebid_cache_client.Client, uuid string) string { return strings.TrimPrefix(cacheURL.String(), "//") } -func listBiddersWithRequests(cleanRequests map[openrtb_ext.BidderName]*openrtb.BidRequest) []openrtb_ext.BidderName { - liveAdapters := make([]openrtb_ext.BidderName, len(cleanRequests)) +func listBiddersWithRequests(bidderRequests []BidderRequest) []openrtb_ext.BidderName { + liveAdapters := make([]openrtb_ext.BidderName, len(bidderRequests)) i := 0 - for a := range cleanRequests { - liveAdapters[i] = a + for _, bidderRequest := range bidderRequests { + liveAdapters[i] = bidderRequest.BidderName i++ } // Randomize the list of adapters to make the auction more fair diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index c2db87133ae..1d32ca3c6d1 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -1152,18 +1152,10 @@ func TestPanicRecovery(t *testing.T) { e := NewExchange(adapters, nil, cfg, &metricsConf.DummyMetricsEngine{}, gdpr.AlwaysAllow{}, currencyConverter, nilCategoryFetcher{}).(*exchange) chBids := make(chan *bidResponseWrapper, 1) - panicker := func(aName openrtb_ext.BidderName, coreBidder openrtb_ext.BidderName, request *openrtb.BidRequest, bidlabels *pbsmetrics.AdapterLabels, conversions currencies.Conversions) { + panicker := func(bidderRequest BidderRequest, conversions currencies.Conversions) { panic("panic!") } - cleanReqs := map[openrtb_ext.BidderName]*openrtb.BidRequest{ - "bidder1": { - ID: "b-1", - }, - "bidder2": { - ID: "b-2", - }, - } - recovered := e.recoverSafely(cleanReqs, panicker, chBids) + apnLabels := pbsmetrics.AdapterLabels{ Source: pbsmetrics.DemandWeb, RType: pbsmetrics.ReqTypeORTB2Web, @@ -1172,7 +1164,27 @@ func TestPanicRecovery(t *testing.T) { CookieFlag: pbsmetrics.CookieFlagYes, AdapterBids: pbsmetrics.AdapterBidNone, } - recovered(openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus, nil, &apnLabels, nil) + + bidderRequests := []BidderRequest{ + { + BidderName: "bidder1", + BidderCoreName: "appnexus", + BidderLabels: apnLabels, + BidRequest: &openrtb.BidRequest{ + ID: "b-1", + }, + }, + { + BidderName: "bidder2", + BidderCoreName: "bidder2", + BidRequest: &openrtb.BidRequest{ + ID: "b-2", + }, + }, + } + + recovered := e.recoverSafely(bidderRequests, panicker, chBids) + recovered(bidderRequests[0], nil) } func buildImpExt(t *testing.T, jsonFilename string) json.RawMessage { diff --git a/exchange/utils.go b/exchange/utils.go index 285f650cbc5..4a1c8bb52b7 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -53,47 +53,43 @@ func BidderToPrebidSChains(req *openrtb_ext.ExtRequest) (map[string]*openrtb_ext // 2. Every BidRequest.Imp[] requested Bids from the Bidder who keys it. // 3. BidRequest.User.BuyerUID will be set to that Bidder's ID. func cleanOpenRTBRequests(ctx context.Context, - orig *openrtb.BidRequest, + req AuctionRequest, requestExt *openrtb_ext.ExtRequest, - usersyncs IdFetcher, - blables map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels, - labels pbsmetrics.Labels, gDPR gdpr.Permissions, usersyncIfAmbiguous bool, - privacyConfig config.Privacy, - account *config.Account) (requestsByBidder map[openrtb_ext.BidderName]*openrtb.BidRequest, aliases map[string]string, privacyLabels pbsmetrics.PrivacyLabels, errs []error) { + privacyConfig config.Privacy) (bidderRequests []BidderRequest, privacyLabels pbsmetrics.PrivacyLabels, errs []error) { - impsByBidder, errs := splitImps(orig.Imp) + impsByBidder, errs := splitImps(req.BidRequest.Imp) if len(errs) > 0 { return } - aliases, errs = parseAliases(orig) + aliases, errs := parseAliases(req.BidRequest) if len(errs) > 0 { return } - requestsByBidder, errs = splitBidRequest(orig, requestExt, impsByBidder, aliases, usersyncs, blables, labels) + bidderRequests, errs = getAuctionBidderRequests(req, requestExt, impsByBidder, aliases) - if len(requestsByBidder) == 0 { + if len(bidderRequests) == 0 { return } - gdpr := extractGDPR(orig, usersyncIfAmbiguous) - consent := extractConsent(orig) - ampGDPRException := (labels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException() + gdpr := extractGDPR(req.BidRequest, usersyncIfAmbiguous) + consent := extractConsent(req.BidRequest) + ampGDPRException := (req.LegacyLabels.RType == pbsmetrics.ReqTypeAMP) && gDPR.AMPException() - ccpaEnforcer, err := extractCCPA(orig, privacyConfig, account, aliases, integrationTypeMap[labels.RType]) + ccpaEnforcer, err := extractCCPA(req.BidRequest, privacyConfig, &req.Account, aliases, integrationTypeMap[req.LegacyLabels.RType]) if err != nil { errs = append(errs, err) return } - lmtEnforcer := extractLMT(orig, privacyConfig) + lmtEnforcer := extractLMT(req.BidRequest, privacyConfig) // request level privacy policies privacyEnforcement := privacy.Enforcement{ - COPPA: orig.Regs != nil && orig.Regs.COPPA == 1, + COPPA: req.BidRequest.Regs != nil && req.BidRequest.Regs.COPPA == 1, LMT: lmtEnforcer.ShouldEnforce(unknownBidder), } @@ -102,7 +98,7 @@ func cleanOpenRTBRequests(ctx context.Context, privacyLabels.COPPAEnforced = privacyEnforcement.COPPA privacyLabels.LMTEnforced = lmtEnforcer.ShouldEnforce(unknownBidder) - gdprEnabled := gdprEnabled(account, privacyConfig, integrationTypeMap[labels.RType]) + gdprEnabled := gdprEnabled(&req.Account, privacyConfig, integrationTypeMap[req.LegacyLabels.RType]) if gdpr == 1 && gdprEnabled { privacyLabels.GDPREnforced = true @@ -114,16 +110,14 @@ func cleanOpenRTBRequests(ctx context.Context, } // bidder level privacy policies - for bidder, bidReq := range requestsByBidder { + for _, bidderRequest := range bidderRequests { // CCPA - privacyEnforcement.CCPA = ccpaEnforcer.ShouldEnforce(bidder.String()) + privacyEnforcement.CCPA = ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) // GDPR if gdpr == 1 && gdprEnabled { - coreBidder := resolveBidder(bidder.String(), aliases) - - var publisherID = labels.PubID - _, geo, id, err := gDPR.PersonalInfoAllowed(ctx, coreBidder, publisherID, consent) + var publisherID = req.LegacyLabels.PubID + _, geo, id, err := gDPR.PersonalInfoAllowed(ctx, bidderRequest.BidderCoreName, publisherID, consent) privacyEnforcement.GDPRGeo = !geo && err == nil privacyEnforcement.GDPRID = !id && err == nil } else { @@ -131,7 +125,7 @@ func cleanOpenRTBRequests(ctx context.Context, privacyEnforcement.GDPRID = false } - privacyEnforcement.Apply(bidReq, ampGDPRException) + privacyEnforcement.Apply(bidderRequest.BidRequest, ampGDPRException) } return @@ -177,16 +171,14 @@ func extractLMT(orig *openrtb.BidRequest, privacyConfig config.Privacy) privacy. } } -func splitBidRequest(req *openrtb.BidRequest, +func getAuctionBidderRequests(req AuctionRequest, requestExt *openrtb_ext.ExtRequest, impsByBidder map[string][]openrtb.Imp, - aliases map[string]string, - usersyncs IdFetcher, - blabels map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels, - labels pbsmetrics.Labels) (map[openrtb_ext.BidderName]*openrtb.BidRequest, []error) { + aliases map[string]string) ([]BidderRequest, []error) { + + bidderRequests := make([]BidderRequest, 0, len(impsByBidder)) - requestsByBidder := make(map[openrtb_ext.BidderName]*openrtb.BidRequest, len(impsByBidder)) - explicitBuyerUIDs, err := extractBuyerUIDs(req.User) + explicitBuyerUIDs, err := extractBuyerUIDs(req.BidRequest.User) if err != nil { return nil, []error{err} } @@ -198,36 +190,41 @@ func splitBidRequest(req *openrtb.BidRequest, return nil, []error{err} } - reqExt, err := getExtJson(req, requestExt) + reqExt, err := getExtJson(req.BidRequest, requestExt) if err != nil { return nil, []error{err} } for bidder, imps := range impsByBidder { - reqCopy := *req coreBidder := resolveBidder(bidder, aliases) - newLabel := pbsmetrics.AdapterLabels{ - Source: labels.Source, - RType: labels.RType, - Adapter: coreBidder, - PubID: labels.PubID, - CookieFlag: labels.CookieFlag, - AdapterBids: pbsmetrics.AdapterBidPresent, + + reqCopy := *req.BidRequest + reqCopy.Imp = imps + reqCopy.Ext = reqExt + prepareSource(&reqCopy, bidder, sChainsByBidder) + + bidder := BidderRequest{ + BidderName: openrtb_ext.BidderName(bidder), + BidderCoreName: coreBidder, + BidRequest: &reqCopy, + BidderLabels: pbsmetrics.AdapterLabels{ + Source: req.LegacyLabels.Source, + RType: req.LegacyLabels.RType, + Adapter: coreBidder, + PubID: req.LegacyLabels.PubID, + CookieFlag: req.LegacyLabels.CookieFlag, + AdapterBids: pbsmetrics.AdapterBidPresent, + }, } - blabels[coreBidder] = &newLabel - if hadSync := prepareUser(&reqCopy, bidder, coreBidder, explicitBuyerUIDs, usersyncs); !hadSync && req.App == nil { - blabels[coreBidder].CookieFlag = pbsmetrics.CookieFlagNo + if hadSync := prepareUser(&reqCopy, bidder.BidderName.String(), coreBidder, explicitBuyerUIDs, req.UserSyncs); !hadSync && req.BidRequest.App == nil { + bidder.BidderLabels.CookieFlag = pbsmetrics.CookieFlagNo } else { - blabels[coreBidder].CookieFlag = pbsmetrics.CookieFlagYes + bidder.BidderLabels.CookieFlag = pbsmetrics.CookieFlagYes } - reqCopy.Imp = imps - - prepareSource(&reqCopy, bidder, sChainsByBidder) - reqCopy.Ext = reqExt - requestsByBidder[openrtb_ext.BidderName(bidder)] = &reqCopy + bidderRequests = append(bidderRequests, bidder) } - return requestsByBidder, nil + return bidderRequests, nil } func getExtJson(req *openrtb.BidRequest, unpackedExt *openrtb_ext.ExtRequest) (json.RawMessage, error) { diff --git a/exchange/utils_test.go b/exchange/utils_test.go index e2aa72e04fc..2f24af2a06c 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -38,38 +38,48 @@ func (p *permissionsMock) AMPException() bool { return false } -func assertReq(t *testing.T, reqByBidders map[openrtb_ext.BidderName]*openrtb.BidRequest, +func assertReq(t *testing.T, bidderRequests []BidderRequest, applyCOPPA bool, consentedVendors map[string]bool) { // assert individual bidder requests - assert.NotEqual(t, reqByBidders, 0, "cleanOpenRTBRequest should split request into individual bidder requests") + assert.NotEqual(t, bidderRequests, 0, "cleanOpenRTBRequest should split request into individual bidder requests") // assert for PI data // Both appnexus and brightroll should be allowed since brightroll // is used as an alias for appnexus in the test request - for bidderName, bidder := range reqByBidders { - if !applyCOPPA && consentedVendors[bidderName.String()] { - assert.NotEqual(t, bidder.User.BuyerUID, "", "cleanOpenRTBRequest shouldn't clean PI data as per COPPA or for a consented vendor as per GDPR or per CCPA") - assert.NotEqual(t, bidder.Device.DIDMD5, "", "cleanOpenRTBRequest shouldn't clean PI data as per COPPA or for a consented vendor as per GDPR or per CCPA") + for _, req := range bidderRequests { + if !applyCOPPA && consentedVendors[req.BidderName.String()] { + assert.NotEqual(t, req.BidRequest.User.BuyerUID, "", "cleanOpenRTBRequest shouldn't clean PI data as per COPPA or for a consented vendor as per GDPR or per CCPA") + assert.NotEqual(t, req.BidRequest.Device.DIDMD5, "", "cleanOpenRTBRequest shouldn't clean PI data as per COPPA or for a consented vendor as per GDPR or per CCPA") } else { - assert.Equal(t, bidder.User.BuyerUID, "", "cleanOpenRTBRequest should clean PI data as per COPPA or for a non-consented vendor as per GDPR or per CCPA", bidderName.String()) - assert.Equal(t, bidder.Device.DIDMD5, "", "cleanOpenRTBRequest should clean PI data as per COPPA or for a non-consented vendor as per GDPR or per CCPA", bidderName.String()) + assert.Equal(t, req.BidRequest.User.BuyerUID, "", "cleanOpenRTBRequest should clean PI data as per COPPA or for a non-consented vendor as per GDPR or per CCPA", req.BidderName.String()) + assert.Equal(t, req.BidRequest.Device.DIDMD5, "", "cleanOpenRTBRequest should clean PI data as per COPPA or for a non-consented vendor as per GDPR or per CCPA", req.BidderName.String()) } } } func TestCleanOpenRTBRequests(t *testing.T) { testCases := []struct { - req *openrtb.BidRequest - bidReqAssertions func(t *testing.T, reqByBidders map[openrtb_ext.BidderName]*openrtb.BidRequest, + req AuctionRequest + bidReqAssertions func(t *testing.T, bidderRequests []BidderRequest, applyCOPPA bool, consentedVendors map[string]bool) hasError bool applyCOPPA bool consentedVendors map[string]bool }{ - {req: newRaceCheckingRequest(t), bidReqAssertions: assertReq, hasError: false, - applyCOPPA: true, consentedVendors: map[string]bool{"appnexus": true}}, - {req: newAdapterAliasBidRequest(t), bidReqAssertions: assertReq, hasError: false, - applyCOPPA: false, consentedVendors: map[string]bool{"appnexus": true, "brightroll": true}}, + { + req: AuctionRequest{BidRequest: newRaceCheckingRequest(t), UserSyncs: &emptyUsersync{}}, + bidReqAssertions: assertReq, + hasError: false, + applyCOPPA: true, + consentedVendors: map[string]bool{"appnexus": true}, + }, + { + req: AuctionRequest{BidRequest: newAdapterAliasBidRequest(t), UserSyncs: &emptyUsersync{}}, + bidReqAssertions: assertReq, + hasError: false, + applyCOPPA: false, + consentedVendors: map[string]bool{"appnexus": true, "brightroll": true}, + }, } privacyConfig := config.Privacy{ @@ -82,12 +92,12 @@ func TestCleanOpenRTBRequests(t *testing.T) { } for _, test := range testCases { - reqByBidders, _, _, err := cleanOpenRTBRequests(context.Background(), test.req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig, &config.Account{}) + bidderRequests, _, err := cleanOpenRTBRequests(context.Background(), test.req, nil, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig) if test.hasError { assert.NotNil(t, err, "Error shouldn't be nil") } else { assert.Nil(t, err, "Err should be nil") - test.bidReqAssertions(t, reqByBidders, test.applyCOPPA, test.consentedVendors) + test.bidReqAssertions(t, bidderRequests, test.applyCOPPA, test.consentedVendors) } } } @@ -227,26 +237,28 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) { }, } - results, _, privacyLabels, errs := cleanOpenRTBRequests( + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + Account: accountConfig, + } + + bidderRequests, privacyLabels, errs := cleanOpenRTBRequests( context.Background(), - req, + auctionReq, nil, - &emptyUsersync{}, - map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, - pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, - privacyConfig, - &accountConfig) - result := results["appnexus"] + privacyConfig) + result := bidderRequests[0] assert.Nil(t, errs) if test.expectDataScrub { - assert.Equal(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.Equal(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.Equal(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.Equal(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } else { - assert.NotEqual(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.NotEqual(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.NotEqual(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.NotEqual(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } assert.Equal(t, test.expectPrivacyLabels, privacyLabels, test.description+":PrivacyLabels") } @@ -282,12 +294,17 @@ func TestCleanOpenRTBRequestsCCPAErrors(t *testing.T) { err := json.Unmarshal(req.Ext, &reqExtStruct) assert.NoError(t, err, test.description+":marshal_ext") + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + } + privacyConfig := config.Privacy{ CCPA: config.CCPA{ Enforce: true, }, } - _, _, _, errs := cleanOpenRTBRequests(context.Background(), req, &reqExtStruct, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig, &config.Account{}) + _, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, &reqExtStruct, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig) assert.ElementsMatch(t, []error{test.expectError}, errs, test.description) } @@ -322,16 +339,21 @@ func TestCleanOpenRTBRequestsCOPPA(t *testing.T) { req := newBidRequest(t) req.Regs = &openrtb.Regs{COPPA: test.coppa} - results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, config.Privacy{}, &config.Account{}) - result := results["appnexus"] + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + } + + bidderRequests, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissionsMock{personalInfoAllowed: true}, true, config.Privacy{}) + result := bidderRequests[0] assert.Nil(t, errs) if test.expectDataScrub { - assert.Equal(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.Equal(t, result.User.Yob, int64(0), test.description+":User.Yob") + assert.Equal(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.Equal(t, result.BidRequest.User.Yob, int64(0), test.description+":User.Yob") } else { - assert.NotEqual(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.NotEqual(t, result.User.Yob, int64(0), test.description+":User.Yob") + assert.NotEqual(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.NotEqual(t, result.BidRequest.User.Yob, int64(0), test.description+":User.Yob") } assert.Equal(t, test.expectPrivacyLabels, privacyLabels, test.description+":PrivacyLabels") } @@ -424,16 +446,20 @@ func TestCleanOpenRTBRequestsSChain(t *testing.T) { extRequest = unmarshaledExt } - results, _, _, errs := cleanOpenRTBRequests(context.Background(), req, extRequest, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{}, true, config.Privacy{}, &config.Account{}) - result := results["appnexus"] + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + } + bidderRequests, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, &permissionsMock{}, true, config.Privacy{}) if test.hasError == true { assert.NotNil(t, errs) - assert.Nil(t, result) + assert.Len(t, bidderRequests, 0) } else { + result := bidderRequests[0] assert.Nil(t, errs) - assert.Equal(t, test.outSourceExt, result.Source.Ext, test.description+":Source.Ext") - assert.Equal(t, test.outRequestExt, result.Ext, test.description+":Ext") + assert.Equal(t, test.outSourceExt, result.BidRequest.Source.Ext, test.description+":Source.Ext") + assert.Equal(t, test.outRequestExt, result.BidRequest.Ext, test.description+":Ext") } } } @@ -995,22 +1021,27 @@ func TestCleanOpenRTBRequestsLMT(t *testing.T) { req := newBidRequest(t) req.Device.Lmt = test.lmt + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + } + privacyConfig := config.Privacy{ LMT: config.LMT{ Enforce: test.enforceLMT, }, } - results, _, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), req, nil, &emptyUsersync{}, map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig, &config.Account{}) - result := results["appnexus"] + results, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissionsMock{personalInfoAllowed: true}, true, privacyConfig) + result := results[0] assert.Nil(t, errs) if test.expectDataScrub { - assert.Equal(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.Equal(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.Equal(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.Equal(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } else { - assert.NotEqual(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.NotEqual(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.NotEqual(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.NotEqual(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } assert.Equal(t, test.expectPrivacyLabels, privacyLabels, test.description+":PrivacyLabels") } @@ -1148,26 +1179,28 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) { }, } - results, _, privacyLabels, errs := cleanOpenRTBRequests( + auctionReq := AuctionRequest{ + BidRequest: req, + UserSyncs: &emptyUsersync{}, + Account: accountConfig, + } + + results, privacyLabels, errs := cleanOpenRTBRequests( context.Background(), - req, + auctionReq, nil, - &emptyUsersync{}, - map[openrtb_ext.BidderName]*pbsmetrics.AdapterLabels{}, - pbsmetrics.Labels{}, &permissionsMock{personalInfoAllowed: !test.gdprScrub}, true, - privacyConfig, - &accountConfig) - result := results["appnexus"] + privacyConfig) + result := results[0] assert.Nil(t, errs) if test.gdprScrub { - assert.Equal(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.Equal(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.Equal(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.Equal(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } else { - assert.NotEqual(t, result.User.BuyerUID, "", test.description+":User.BuyerUID") - assert.NotEqual(t, result.Device.DIDMD5, "", test.description+":Device.DIDMD5") + assert.NotEqual(t, result.BidRequest.User.BuyerUID, "", test.description+":User.BuyerUID") + assert.NotEqual(t, result.BidRequest.Device.DIDMD5, "", test.description+":Device.DIDMD5") } assert.Equal(t, test.expectPrivacyLabels, privacyLabels, test.description+":PrivacyLabels") }