From 0c56b144a9d684d668f725051f186172361ce2a4 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 15:59:02 +0200 Subject: [PATCH 01/16] feat: add beop.json bidder params --- static/bidder-params/beop.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 static/bidder-params/beop.json diff --git a/static/bidder-params/beop.json b/static/bidder-params/beop.json new file mode 100644 index 00000000000..8b34ac91f70 --- /dev/null +++ b/static/bidder-params/beop.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "BeOp Adapter Params", + "description": "A schema which validates params accepted by the BeOp adapter", + "type": "object", + "properties": { + "pid": { + "type": "string", + "description": "Beop publisher ID" + }, + "nid": { + "type": "string", + "description": "Beop Network ID" + }, + "ntpnid": { + "type": "string", + "description": "Network partner ID" + } + }, + "oneOf": [ + { + "required": [ + "pid" + ] + }, + { + "required": [ + "nid", + "ntpnid" + ] + } + ] +} From 3b044f2fa023020f15032b5c3eee154ea91d212d Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 16:00:49 +0200 Subject: [PATCH 02/16] feat: add beop.yaml bidder info --- static/bidder-info/beop.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 static/bidder-info/beop.yaml diff --git a/static/bidder-info/beop.yaml b/static/bidder-info/beop.yaml new file mode 100644 index 00000000000..1129818f857 --- /dev/null +++ b/static/bidder-info/beop.yaml @@ -0,0 +1,12 @@ +endpoint: "https://hb.collectiveaudience.co/rtb/bid" +endpointCompression: gzip +maintainer: + email: tech@collectiveaudience.co +gvlVendorID: 666 +openrtb: + version: 2.6 +capabilities: + site: + mediaTypes: + - banner + - video From db6bc4e0c29fa90444e3019b3d8d52432927a16a Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 16:01:15 +0200 Subject: [PATCH 03/16] feat: add imp_beop.go --- openrtb_ext/imp_beop.go | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 openrtb_ext/imp_beop.go diff --git a/openrtb_ext/imp_beop.go b/openrtb_ext/imp_beop.go new file mode 100644 index 00000000000..797ac92ef02 --- /dev/null +++ b/openrtb_ext/imp_beop.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpBeop struct { + BeopPublisherID string `json:"pid,omitempty"` + BeopNetworkID string `json:"nid,omitempty"` + BeopNetworkPartnerID string `json:"nptnid,omitempty"` +} From b0b4833c949aa4c0985ea5d0d6d9a1ecf0044264 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 16:02:03 +0200 Subject: [PATCH 04/16] feat: add beop.go adapter --- adapters/beop/beop.go | 178 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 adapters/beop/beop.go diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go new file mode 100644 index 00000000000..6a0f99cb220 --- /dev/null +++ b/adapters/beop/beop.go @@ -0,0 +1,178 @@ +package beop + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder( + bidderName openrtb_ext.BidderName, + config config.Adapter, + server config.Server) ( + adapters.Bidder, error, +) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) getRequestExtImpBeop(imp *openrtb2.Imp) (*openrtb_ext.ExtImpBeop, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + var beopExt openrtb_ext.ExtImpBeop + if err := jsonutil.Unmarshal(bidderExt.Bidder, &beopExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + if beopExt.BeopPublisherID == "" && beopExt.BeopNetworkID == "" { + return nil, &errortypes.BadInput{ + Message: "Missing pid or nid parameters", + } + } + return &beopExt, nil +} + +func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpBeop) (string, error) { + url, err := url.Parse(a.endpoint) + if err != nil { + return "", &errortypes.Warning{ + Message: "Failed to parse endpoint", + } + } + query := url.Query() + if pid := params.BeopPublisherID; len(pid) != 0 { + query.Set("pid", pid) + } + if nid := params.BeopNetworkID; len(nid) != 0 { + query.Set("nid", nid) + } + if nptnid := params.BeopNetworkPartnerID; len(nptnid) != 0 { + query.Set("nptnid", nptnid) + } + url.RawQuery = query.Encode() + return url.String(), nil +} + +func (a *adapter) MakeRequests( + request *openrtb2.BidRequest, + requestInfo *adapters.ExtraRequestInfo) ( + []*adapters.RequestData, []error, +) { + var beopExt *openrtb_ext.ExtImpBeop + var err error + + beopExt, err = a.getRequestExtImpBeop(&request.Imp[0]) + if err != nil { + return nil, []error{err} + } + + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + url, err := a.buildEndpointURL(beopExt) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: url, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil && bidExt.Prebid != nil { + return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) + } + } + + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID), + } +} + +func (a *adapter) MakeBids( + request *openrtb2.BidRequest, + requestData *adapters.RequestData, + responseData *adapters.ResponseData) ( + *adapters.BidderResponse, []error, +) { + if responseData.StatusCode == http.StatusNoContent { + return nil, nil + } + + if responseData.StatusCode == http.StatusServiceUnavailable { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Service Unavailable. Status Code: [ %d ] ", responseData.StatusCode), + }} + } + + if responseData.StatusCode == http.StatusBadRequest { + err := &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + var responseBody openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &responseBody); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + if len(responseBody.SeatBid) == 0 { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Empty SeatBid array", + }} + } + + bidResponseFinal := adapters.NewBidderResponseWithBidsCapacity(len(responseBody.SeatBid[0].Bid)) + seatBid := responseBody.SeatBid[0] + var errors []error + for _, bid := range seatBid.Bid { + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bidResponseFinal.Bids = append(bidResponseFinal.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + return bidResponseFinal, errors +} From 70e78964c009c7d29c672c05771f416727affd64 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 16:02:19 +0200 Subject: [PATCH 05/16] feat: register beop adapter --- exchange/adapter_builders.go | 2 ++ openrtb_ext/bidders.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e025eb0ed3c..a649edbced3 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -55,6 +55,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/beachfront" "github.com/prebid/prebid-server/v3/adapters/beintoo" "github.com/prebid/prebid-server/v3/adapters/bematterfull" + "github.com/prebid/prebid-server/v3/adapters/beop" "github.com/prebid/prebid-server/v3/adapters/between" "github.com/prebid/prebid-server/v3/adapters/beyondmedia" "github.com/prebid/prebid-server/v3/adapters/bidmachine" @@ -320,6 +321,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBeachfront: beachfront.Builder, openrtb_ext.BidderBeintoo: beintoo.Builder, openrtb_ext.BidderBematterfull: bematterfull.Builder, + openrtb_ext.BidderBeop: beop.Builder, openrtb_ext.BidderBetween: between.Builder, openrtb_ext.BidderBeyondMedia: beyondmedia.Builder, openrtb_ext.BidderBidmachine: bidmachine.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index cdb6dcd2c7c..d7e3ae351f4 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -71,6 +71,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderBeachfront, BidderBeintoo, BidderBematterfull, + BidderBeop, BidderBetween, BidderBeyondMedia, BidderBidmachine, @@ -443,6 +444,7 @@ const ( BidderBeachfront BidderName = "beachfront" BidderBeintoo BidderName = "beintoo" BidderBematterfull BidderName = "bematterfull" + BidderBeop BidderName = "beop" BidderBetween BidderName = "between" BidderBeyondMedia BidderName = "beyondmedia" BidderBidmachine BidderName = "bidmachine" From 68f08c59556dadd31a8577703d6ce73b4e711409 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 22 Oct 2025 16:02:49 +0200 Subject: [PATCH 06/16] feat: add beop adapter test --- adapters/beop/beop_test.go | 21 +++ .../exemplary/banner-web-with-nid.json | 153 +++++++++++++++++ .../beop/beoptest/exemplary/banner-web.json | 151 ++++++++++++++++ .../beop/beoptest/exemplary/video-web.json | 161 ++++++++++++++++++ .../supplemental/empty-seatbid-array.json | 111 ++++++++++++ .../supplemental/invalid-response.json | 104 +++++++++++ .../supplemental/status-code-bad-request.json | 104 +++++++++++ .../status-code-service-unavailable.json | 104 +++++++++++ 8 files changed, 909 insertions(+) create mode 100644 adapters/beop/beop_test.go create mode 100644 adapters/beop/beoptest/exemplary/banner-web-with-nid.json create mode 100644 adapters/beop/beoptest/exemplary/banner-web.json create mode 100644 adapters/beop/beoptest/exemplary/video-web.json create mode 100644 adapters/beop/beoptest/supplemental/empty-seatbid-array.json create mode 100644 adapters/beop/beoptest/supplemental/invalid-response.json create mode 100644 adapters/beop/beoptest/supplemental/status-code-bad-request.json create mode 100644 adapters/beop/beoptest/supplemental/status-code-service-unavailable.json diff --git a/adapters/beop/beop_test.go b/adapters/beop/beop_test.go new file mode 100644 index 00000000000..5960bc09f1c --- /dev/null +++ b/adapters/beop/beop_test.go @@ -0,0 +1,21 @@ +package beop + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBeop, config.Adapter{ + Endpoint: "http://hb-test.collectiveaudience.co/rtb/bid"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "beoptest", bidder) +} diff --git a/adapters/beop/beoptest/exemplary/banner-web-with-nid.json b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json new file mode 100644 index 00000000000..b5a30850439 --- /dev/null +++ b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", + "nptnid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?nid=aaaaaaaaaaaaaaaaaaaaaaaa&nptnid=1234", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", + "nptnid": "1234" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/exemplary/banner-web.json b/adapters/beop/beoptest/exemplary/banner-web.json new file mode 100644 index 00000000000..d7d962318f9 --- /dev/null +++ b/adapters/beop/beoptest/exemplary/banner-web.json @@ -0,0 +1,151 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/exemplary/video-web.json b/adapters/beop/beoptest/exemplary/video-web.json new file mode 100644 index 00000000000..b7208935a29 --- /dev/null +++ b/adapters/beop/beoptest/exemplary/video-web.json @@ -0,0 +1,161 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/empty-seatbid-array.json b/adapters/beop/beoptest/supplemental/empty-seatbid-array.json new file mode 100644 index 00000000000..0b709b2b935 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/empty-seatbid-array.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [] + } + } + } + ], + "mockResponse": { + "status": 200, + "body": "invalid response" + }, + "expectedMakeBidsErrors": [ + { + "value": "Empty SeatBid array", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/invalid-response.json b/adapters/beop/beoptest/supplemental/invalid-response.json new file mode 100644 index 00000000000..8c5537acefd --- /dev/null +++ b/adapters/beop/beoptest/supplemental/invalid-response.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/status-code-bad-request.json b/adapters/beop/beoptest/supplemental/status-code-bad-request.json new file mode 100644 index 00000000000..f8c0eb2d564 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-bad-request.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info.", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json b/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json new file mode 100644 index 00000000000..ce3742ab852 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 503 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Service Unavailable. Status Code: [ 503 ] ", + "comparison": "literal" + } + ] +} From 64e60bfd8880cac0f21dd33a921c839bd29d5431 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Thu, 22 Jan 2026 11:02:33 +0100 Subject: [PATCH 07/16] refacto: update bid reference --- adapters/beop/beop.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index 6a0f99cb220..c097f72c6a6 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -163,14 +163,15 @@ func (a *adapter) MakeBids( bidResponseFinal := adapters.NewBidderResponseWithBidsCapacity(len(responseBody.SeatBid[0].Bid)) seatBid := responseBody.SeatBid[0] var errors []error - for _, bid := range seatBid.Bid { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] bidType, err := getMediaTypeForBid(bid) if err != nil { errors = append(errors, err) continue } bidResponseFinal.Bids = append(bidResponseFinal.Bids, &adapters.TypedBid{ - Bid: &bid, + Bid: bid, BidType: bidType, }) } From 77c9c14c6a8acf80d352812d53ae40bc042c722c Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Thu, 22 Jan 2026 11:03:10 +0100 Subject: [PATCH 08/16] refacto: use mtype field --- adapters/beop/beop.go | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index c097f72c6a6..8466e3b00a0 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -110,18 +110,22 @@ func (a *adapter) MakeRequests( return []*adapters.RequestData{requestData}, nil } -func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { - if bid.Ext != nil { - var bidExt openrtb_ext.ExtBid - err := jsonutil.Unmarshal(bid.Ext, &bidExt) - if err == nil && bidExt.Prebid != nil { - return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) - } - } - - return "", &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID), - } +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + mType := bid.MType + var bidType openrtb_ext.BidType + switch mType { + case openrtb2.MarkupBanner: + bidType = openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + bidType = openrtb_ext.BidTypeVideo + case openrtb2.MarkupAudio: + bidType = openrtb_ext.BidTypeAudio + case openrtb2.MarkupNative: + bidType = openrtb_ext.BidTypeNative + default: + return bidType, fmt.Errorf("Failed to parse bid mType for impression \"%s\"", bid.ImpID) + } + return bidType, nil } func (a *adapter) MakeBids( From 49abbe904b6686859791fc8f556ff7f25c3a5329 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Thu, 22 Jan 2026 11:03:22 +0100 Subject: [PATCH 09/16] refacto: tests --- adapters/beop/beoptest/exemplary/banner-web-with-nid.json | 2 ++ adapters/beop/beoptest/exemplary/banner-web.json | 2 ++ adapters/beop/beoptest/exemplary/video-web.json | 2 ++ 3 files changed, 6 insertions(+) diff --git a/adapters/beop/beoptest/exemplary/banner-web-with-nid.json b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json index b5a30850439..e0c6f9a880c 100644 --- a/adapters/beop/beoptest/exemplary/banner-web-with-nid.json +++ b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json @@ -110,6 +110,7 @@ "crid": "100", "w": 320, "h": 50, + "mtype": 1, "ext": { "prebid": { "type": "banner" @@ -139,6 +140,7 @@ "crid": "100", "w": 320, "h": 50, + "mtype": 1, "ext": { "prebid": { "type": "banner" diff --git a/adapters/beop/beoptest/exemplary/banner-web.json b/adapters/beop/beoptest/exemplary/banner-web.json index d7d962318f9..a757171e346 100644 --- a/adapters/beop/beoptest/exemplary/banner-web.json +++ b/adapters/beop/beoptest/exemplary/banner-web.json @@ -108,6 +108,7 @@ "crid": "100", "w": 320, "h": 50, + "mtype": 1, "ext": { "prebid": { "type": "banner" @@ -137,6 +138,7 @@ "crid": "100", "w": 320, "h": 50, + "mtype": 1, "ext": { "prebid": { "type": "banner" diff --git a/adapters/beop/beoptest/exemplary/video-web.json b/adapters/beop/beoptest/exemplary/video-web.json index b7208935a29..bd4ff7acfec 100644 --- a/adapters/beop/beoptest/exemplary/video-web.json +++ b/adapters/beop/beoptest/exemplary/video-web.json @@ -118,6 +118,7 @@ "crid": "100", "w": 1280, "h": 720, + "mtype": 2, "ext": { "prebid": { "type": "video" @@ -147,6 +148,7 @@ "crid": "100", "w": 1280, "h": 720, + "mtype": 2, "ext": { "prebid": { "type": "video" From d8f8a75f4ab814af8f52d81891c8d5e72e101ff2 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Fri, 13 Feb 2026 16:15:40 +0100 Subject: [PATCH 10/16] review: remove extra cases --- adapters/beop/beop.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index 8466e3b00a0..c1d83baf3b5 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -118,10 +118,6 @@ func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { bidType = openrtb_ext.BidTypeBanner case openrtb2.MarkupVideo: bidType = openrtb_ext.BidTypeVideo - case openrtb2.MarkupAudio: - bidType = openrtb_ext.BidTypeAudio - case openrtb2.MarkupNative: - bidType = openrtb_ext.BidTypeNative default: return bidType, fmt.Errorf("Failed to parse bid mType for impression \"%s\"", bid.ImpID) } From acb9c44b81e294f4e290e149ba4641c60ebdd202 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Fri, 13 Feb 2026 16:55:15 +0100 Subject: [PATCH 11/16] review: remove extra validation --- adapters/beop/beop.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index c1d83baf3b5..2493c92ee98 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -43,11 +43,6 @@ func (a *adapter) getRequestExtImpBeop(imp *openrtb2.Imp) (*openrtb_ext.ExtImpBe Message: "ext.bidder not provided", } } - if beopExt.BeopPublisherID == "" && beopExt.BeopNetworkID == "" { - return nil, &errortypes.BadInput{ - Message: "Missing pid or nid parameters", - } - } return &beopExt, nil } From d8643a6a8f0adee20dee71d8178b6e6564b7bded Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Fri, 13 Feb 2026 16:55:40 +0100 Subject: [PATCH 12/16] review: remove url parse error check --- adapters/beop/beop.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index 2493c92ee98..a8fb45c8d5d 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -47,12 +47,7 @@ func (a *adapter) getRequestExtImpBeop(imp *openrtb2.Imp) (*openrtb_ext.ExtImpBe } func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpBeop) (string, error) { - url, err := url.Parse(a.endpoint) - if err != nil { - return "", &errortypes.Warning{ - Message: "Failed to parse endpoint", - } - } + url, _ := url.Parse(a.endpoint) query := url.Query() if pid := params.BeopPublisherID; len(pid) != 0 { query.Set("pid", pid) From 42bba130f1b1d08ddb802599a32648553d967b93 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Fri, 13 Feb 2026 18:05:04 +0100 Subject: [PATCH 13/16] review: add missing bidder params test --- .../supplemental/missing-bidder-params.json | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 adapters/beop/beoptest/supplemental/missing-bidder-params.json diff --git a/adapters/beop/beoptest/supplemental/missing-bidder-params.json b/adapters/beop/beoptest/supplemental/missing-bidder-params.json new file mode 100644 index 00000000000..4c2de07072d --- /dev/null +++ b/adapters/beop/beoptest/supplemental/missing-bidder-params.json @@ -0,0 +1,41 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": {} + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "ext.bidder not provided", + "comparison": "literal" + } + ] +} From a5cb34d504ebd4e3d41524a4e5cdfbba54de86fc Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Fri, 13 Feb 2026 18:05:38 +0100 Subject: [PATCH 14/16] review: add invalid bid type test --- adapters/beop/beop.go | 3 + .../supplemental/invalid-bid-type.json | 131 ++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 adapters/beop/beoptest/supplemental/invalid-bid-type.json diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index a8fb45c8d5d..ffbb4c94bd8 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -165,5 +165,8 @@ func (a *adapter) MakeBids( BidType: bidType, }) } + if len(bidResponseFinal.Bids) == 0 { + return nil, errors + } return bidResponseFinal, errors } diff --git a/adapters/beop/beoptest/supplemental/invalid-bid-type.json b/adapters/beop/beoptest/supplemental/invalid-bid-type.json new file mode 100644 index 00000000000..d0a8580963d --- /dev/null +++ b/adapters/beop/beoptest/supplemental/invalid-bid-type.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 3, + "ext": { + "prebid": { + "type": "audio" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Failed to parse bid mType for impression \"impression-id\"", + "comparison": "literal" + } + ] +} From ae27191291234d07dde33c7c22ba6cdf9f23331a Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 18 Feb 2026 10:42:19 +0100 Subject: [PATCH 15/16] review: add params_test --- adapters/beop/params_test.go | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 adapters/beop/params_test.go diff --git a/adapters/beop/params_test.go b/adapters/beop/params_test.go new file mode 100644 index 00000000000..5b854bd3af5 --- /dev/null +++ b/adapters/beop/params_test.go @@ -0,0 +1,49 @@ +package beop + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderBeop, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected adverxo params: %s", validParam) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderBeop, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{ "pid": "aaaaaaaaaaaaaaaaaaaaaaaa"}`, + `{ "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", "ntpnid": "1234"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `{}`, + `{ "fid": 5 }`, + `{ "pid": 5 }`, + `{ "pid": 5 }`, + `{ "nid": "", "nptnid": "" }`, +} From 963f154eae12452c938e99873f43a69d0cb098e2 Mon Sep 17 00:00:00 2001 From: Jean BOUDET Date: Wed, 18 Feb 2026 10:42:34 +0100 Subject: [PATCH 16/16] review: add status code no content test --- .../supplemental/status-code-no-content.json | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 adapters/beop/beoptest/supplemental/status-code-no-content.json diff --git a/adapters/beop/beoptest/supplemental/status-code-no-content.json b/adapters/beop/beoptest/supplemental/status-code-no-content.json new file mode 100644 index 00000000000..25280c2395d --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-no-content.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +}