From 6c8816f48a1e88687925d4c2920ea31b09970fa2 Mon Sep 17 00:00:00 2001 From: Veronika Solovei Date: Thu, 16 Apr 2020 07:55:47 -0700 Subject: [PATCH] Bugfix: no bids from bidder handling (#1252) Co-authored-by: Veronika Solovei --- exchange/exchange.go | 30 ++- exchange/exchange_test.go | 19 +- .../request-multi-bidders-debug-info.json | 227 ++++++++++++++++++ .../request-multi-bidders-one-no-resp.json | 122 ++++++++++ 4 files changed, 386 insertions(+), 12 deletions(-) create mode 100644 exchange/exchangetest/request-multi-bidders-debug-info.json create mode 100644 exchange/exchangetest/request-multi-bidders-one-no-resp.json diff --git a/exchange/exchange.go b/exchange/exchange.go index e625e5ca8f3..48903dd98c7 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -63,6 +63,9 @@ type exchange struct { type seatResponseExtra struct { ResponseTimeMillis int Errors []openrtb_ext.ExtBidderError + // httpCalls is the list of debugging info. It should only be populated if the request.test == 1. + // This will become response.ext.debug.httpcalls.{bidder} on the final Response. + HttpCalls []*openrtb_ext.ExtHttpCall } type bidResponseWrapper struct { @@ -324,6 +327,10 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext // Structure to record extra tracking data generated during bidding ae := new(seatResponseExtra) ae.ResponseTimeMillis = int(elapsed / time.Millisecond) + if bids != nil { + ae.HttpCalls = bids.httpCalls + } + // Timing statistics e.me.RecordAdapterTime(*bidlabels, time.Since(start)) serr := errsToBidderErrors(err) @@ -346,7 +353,12 @@ func (e *exchange) getAllBids(ctx context.Context, cleanRequests map[openrtb_ext // Wait for the bidders to do their thing for i := 0; i < len(cleanRequests); i++ { brw := <-chBids - adapterBids[brw.bidder] = brw.adapterBids + + //if bidder returned no bids back - remove bidder from further processing + if brw.adapterBids != nil && len(brw.adapterBids.bids) != 0 { + adapterBids[brw.bidder] = brw.adapterBids + } + //but we need to add all bidders data to adapterExtra to have metrics and other metadata adapterExtra[brw.bidder] = brw.adapterExtra if !bidsFound && adapterBids[brw.bidder] != nil && len(adapterBids[brw.bidder].bids) > 0 { @@ -639,20 +651,20 @@ func (e *exchange) makeExtBidResponse(adapterBids map[openrtb_ext.BidderName]*pb } } - for a, b := range adapterBids { - if b != nil && req.Test == 1 { - // Fill debug info - bidResponseExt.Debug.HttpCalls[a] = b.httpCalls + for bidderName, responseExtra := range adapterExtra { + + if req.Test == 1 { + bidResponseExt.Debug.HttpCalls[bidderName] = responseExtra.HttpCalls } // Only make an entry for bidder errors if the bidder reported any. - if len(adapterExtra[a].Errors) > 0 { - bidResponseExt.Errors[a] = adapterExtra[a].Errors + if len(responseExtra.Errors) > 0 { + bidResponseExt.Errors[bidderName] = responseExtra.Errors } if len(errList) > 0 { bidResponseExt.Errors[openrtb_ext.PrebidExtKey] = errsToBidderErrors(errList) } - bidResponseExt.ResponseTimeMillis[a] = adapterExtra[a].ResponseTimeMillis - // Defering the filling of bidResponseExt.Usersync[a] until later + bidResponseExt.ResponseTimeMillis[bidderName] = responseExtra.ResponseTimeMillis + // Defering the filling of bidResponseExt.Usersync[bidderName] until later } return bidResponseExt diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index e7df5e85733..3c1c2f3bc72 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -771,6 +771,11 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { } } } + if spec.IncomingRequest.OrtbRequest.Test == 1 { + //compare debug info + diffJson(t, "Debug info modified", bid.Ext, spec.Response.Ext) + + } } func findBiddersInAuction(t *testing.T, context string, req *openrtb.BidRequest) []string { @@ -1625,6 +1630,7 @@ type exchangeRequest struct { type exchangeResponse struct { Bids *openrtb.BidResponse `json:"bids"` Error string `json:"error,omitempty"` + Ext json.RawMessage `json:"ext,omitempty"` } type bidderSpec struct { @@ -1638,8 +1644,9 @@ type bidderRequest struct { } type bidderResponse struct { - SeatBid *bidderSeatBid `json:"pbsSeatBid,omitempty"` - Errors []string `json:"errors,omitempty"` + SeatBid *bidderSeatBid `json:"pbsSeatBid,omitempty"` + Errors []string `json:"errors,omitempty"` + HttpCalls []*openrtb_ext.ExtHttpCall `json:"httpCalls,omitempty"` } // bidderSeatBid is basically a subset of pbsOrtbSeatBid from exchange/bidder.go. @@ -1696,7 +1703,13 @@ func (b *validatingBidder) requestBid(ctx context.Context, request *openrtb.BidR } seatBid = &pbsOrtbSeatBid{ - bids: bids, + bids: bids, + httpCalls: mockResponse.HttpCalls, + } + } else { + seatBid = &pbsOrtbSeatBid{ + bids: nil, + httpCalls: mockResponse.HttpCalls, } } diff --git a/exchange/exchangetest/request-multi-bidders-debug-info.json b/exchange/exchangetest/request-multi-bidders-debug-info.json new file mode 100644 index 00000000000..ec174f75b36 --- /dev/null +++ b/exchange/exchangetest/request-multi-bidders-debug-info.json @@ -0,0 +1,227 @@ +{ + "incomingRequest": { + "ortbRequest": { + "test": 1, + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "appnexus": { + "placementId": 1 + }, + "audienceNetwork": { + "placementId": "some-placement" + } + } + }, + { + "id": "imp-id-2", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "appnexus": { + "placementId": 2 + }, + "audienceNetwork": { + "placementId": "some-other-placement" + } + } + } + ], + "ext": { + "prebid": { + "targeting": { + "durationRangeSec": [ + 15, + 30 + ], + "includebrandcategory": { + "primaryadserver": 1, + "publisher": "", + "withCategory": true, + "translateCategories": true + } + } + } + } + } + }, + "outgoingRequests": { + "appnexus": { + "mockResponse": { + "httpCalls": [ + { + "uri": "appnexusTest.com", + "requestbody": "appnexusTestRequestBody", + "responsebody": "appnexusTestResponseBody", + "status": 200 + } + ], + "pbsSeatBid": { + "pbsBids": [ + { + "ortbBid": { + "id": "winning-bid", + "impid": "my-imp-id", + "price": 12.00, + "w": 200, + "h": 250, + "crid": "creative-1", + "cat": [ + "IAB1-1" + ] + } + } + ] + } + } + }, + "audienceNetwork": { + "mockResponse": { + "httpCalls": [ + { + "uri": "audienceNetworkTest.com", + "requestbody": "audienceNetworkTestRequestBody", + "responsebody": "audienceNetworkTestResponseBody", + "status": 200 + } + ] + } + } + }, + "response": { + "bids": { + "id": "some-request-id", + "seatbid": [ + { + "seat": "appnexus", + "bid": [ + { + "id": "winning-bid", + "impid": "my-imp-id", + "price": 12.00, + "w": 200, + "h": 250, + "crid": "creative-1", + "cat": [ + "IAB1-1" + ], + "ext": { + "prebid": { + "type": "", + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_host": "www.pbcserver.com", + "hb_cache_host_appnex": "www.pbcserver.com", + "hb_cache_path": "/pbcache/endpoint", + "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_size": "200x250", + "hb_size_appnexus": "200x250", + "hb_pb": "12.00", + "hb_pb_appnexus": "12.00", + "hb_pb_cat_dur": "12.00_VideoGames_15s", + "hb_pb_cat_dur_appnex": "12.00_VideoGames_15s" + } + } + } + } + ] + } + ] + }, + "ext": { + "debug": { + "httpcalls": { + "appnexus": [ + { + "uri": "appnexusTest.com", + "requestbody": "appnexusTestRequestBody", + "responsebody": "appnexusTestResponseBody", + "status": 200 + } + ], + "audienceNetwork": [ + { + "uri": "audienceNetworkTest.com", + "requestbody": "audienceNetworkTestRequestBody", + "responsebody": "audienceNetworkTestResponseBody", + "status": 200 + } + ] + }, + "resolvedrequest": { + "id": "some-request-id", + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "appnexus": { + "placementId": 1 + }, + "audienceNetwork": { + "placementId": "some-placement" + } + } + }, + { + "id": "imp-id-2", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "appnexus": { + "placementId": 2 + }, + "audienceNetwork": { + "placementId": "some-other-placement" + } + } + } + ], + "site": { + "page": "test.somepage.com" + }, + "test": 1, + "ext": { + "prebid": { + "targeting": { + "durationRangeSec": [ + 15, + 30 + ], + "includebrandcategory": { + "primaryadserver": 1, + "publisher": "", + "withCategory": true, + "translateCategories": true + } + } + } + } + } + } + } + } +} + + diff --git a/exchange/exchangetest/request-multi-bidders-one-no-resp.json b/exchange/exchangetest/request-multi-bidders-one-no-resp.json new file mode 100644 index 00000000000..b7179ccb02e --- /dev/null +++ b/exchange/exchangetest/request-multi-bidders-one-no-resp.json @@ -0,0 +1,122 @@ +{ + "incomingRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": ["video/mp4"] + }, + "ext": { + "appnexus": { + "placementId": 1 + }, + "audienceNetwork": { + "placementId": "some-placement" + } + } + }, + { + "id": "imp-id-2", + "video": { + "mimes": ["video/mp4"] + }, + "ext": { + "appnexus": { + "placementId": 2 + }, + "audienceNetwork": { + "placementId": "some-other-placement" + } + } + } + ], + "ext": { + "prebid": { + "targeting": { + "durationRangeSec": [15,30], + "includebrandcategory": { + "primaryadserver": 1, + "publisher": "", + "withCategory": true, + "translateCategories": true + } + } + } + } + } + }, + "outgoingRequests": { + "appnexus": { + "mockResponse": { + "pbsSeatBid": { + "pbsBids": [ + { + "ortbBid": { + "id": "winning-bid", + "impid": "my-imp-id", + "price": 12.00, + "w": 200, + "h": 250, + "crid": "creative-1", + "cat": [ + "IAB1-1" + ] + } + } + ] + } + } + }, + "audienceNetwork": { + "mockResponse": { + + } + } + }, + "response": { + "bids": { + "id": "some-request-id", + "seatbid": [ + { + "seat": "appnexus", + "bid": [ + { + "id": "winning-bid", + "impid": "my-imp-id", + "price": 12.00, + "w": 200, + "h": 250, + "crid": "creative-1", + "cat": ["IAB1-1"], + "ext": { + "prebid": { + "type": "", + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_host": "www.pbcserver.com", + "hb_cache_host_appnex": "www.pbcserver.com", + "hb_cache_path": "/pbcache/endpoint", + "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_size": "200x250", + "hb_size_appnexus": "200x250", + "hb_pb": "12.00", + "hb_pb_appnexus": "12.00", + "hb_pb_cat_dur": "12.00_VideoGames_15s", + "hb_pb_cat_dur_appnex": "12.00_VideoGames_15s" + } + } + } + }] + } + ] + } + } +} + +