From 484d41e8f88b7557b32e588d34151ae6f7594f1a Mon Sep 17 00:00:00 2001 From: Volokha Date: Tue, 10 Feb 2026 15:07:33 +0200 Subject: [PATCH 01/12] add rtbstack adapter for pbs --- adapters/rtbstack/rtbstack.go | 190 ++++++++++++++++++ adapters/rtbstack/rtbstack_test.go | 19 ++ .../rtbstacktest/exemplary/app-audio.json | 148 ++++++++++++++ .../rtbstacktest/exemplary/app-banner.json | 128 ++++++++++++ .../rtbstacktest/exemplary/app-native.json | 140 +++++++++++++ .../rtbstacktest/exemplary/app-video.json | 156 ++++++++++++++ .../exemplary/optional-params.json | 177 ++++++++++++++++ .../rtbstacktest/exemplary/site-audio.json | 140 +++++++++++++ .../rtbstacktest/exemplary/site-banner.json | 181 +++++++++++++++++ .../exemplary/site-domain-empty-mutation.json | 59 ++++++ .../exemplary/site-domain-mutation.json | 60 ++++++ .../rtbstacktest/exemplary/site-native.json | 142 +++++++++++++ .../rtbstacktest/exemplary/site-video.json | 152 ++++++++++++++ .../rtbstacktest/supplemental/bad-imp.json | 29 +++ .../supplemental/bad-response.json | 70 +++++++ .../rtbstacktest/supplemental/status-204.json | 58 ++++++ .../rtbstacktest/supplemental/status-400.json | 64 ++++++ .../supplemental/two-imps-one-is-bad.json | 69 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_rtbstack.go | 7 + static/bidder-info/rtbstack.yaml | 16 ++ static/bidder-params/rtbstack.json | 23 +++ 23 files changed, 2032 insertions(+) create mode 100644 adapters/rtbstack/rtbstack.go create mode 100644 adapters/rtbstack/rtbstack_test.go create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/app-audio.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/app-banner.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/app-native.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/app-video.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/optional-params.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-audio.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-banner.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-native.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-video.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-response.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/status-204.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/status-400.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json create mode 100644 openrtb_ext/imp_rtbstack.go create mode 100644 static/bidder-info/rtbstack.yaml create mode 100644 static/bidder-params/rtbstack.json diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go new file mode 100644 index 00000000000..5c5c5e6fdce --- /dev/null +++ b/adapters/rtbstack/rtbstack.go @@ -0,0 +1,190 @@ +package rtbstack + +import ( + "encoding/json" + "fmt" + "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" + "net/http" + "strings" +) + +const endpointMacro = "http://{{.Host}}" + +type adapter struct { + endpoint string +} + +// impCtx represents the context containing an OpenRTB impression and its corresponding RTBStack extension configuration. +type impCtx struct { + imp openrtb2.Imp + rtbStackExt *openrtb_ext.ExtImpRTBStack +} + +// extImpRTBStack is used for imp->ext when sending to rtb-stack backend +type extImpRTBStack struct { + TagId string `json:"tagid"` + CustomParams map[string]interface{} `json:"customParams,omitempty"` +} + +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) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if len(request.Imp) == 0 { + return nil, []error{&errortypes.BadInput{ + Message: "No impressions in request", + }} + } + + var errs []error + var validImps []*impCtx + + for i := range request.Imp { + imp := request.Imp[i] + + ext, err := preprocessImp(&imp) + if err != nil { + errs = append(errs, err) + continue + } + + validImps = append(validImps, &impCtx{ + imp: imp, + rtbStackExt: ext, + }) + } + + if len(validImps) == 0 { + return nil, errs + } + + request.Imp = nil + for _, v := range validImps { + request.Imp = append(request.Imp, v.imp) + } + + endpoint := a.buildEndpointURL(validImps[0].rtbStackExt) + + var newRequest openrtb2.BidRequest + newRequest = *request + + if request.Site != nil && request.Site.Domain == "" { + newSite := *request.Site + newSite.Domain = request.Site.Page + newRequest.Site = &newSite + } + + reqJSON, err := json.Marshal(newRequest) + if err != nil { + return nil, []error{&errortypes.BadInput{ + Message: "Error parsing reqJSON object", + }} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return []*adapters.RequestData{{ + Method: "POST", + Uri: endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }}, []error{} +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if response.StatusCode != http.StatusOK { + return nil, []error{fmt.Errorf("Unexpected status code: %d", response.StatusCode)} + } + + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + if len(bidResp.SeatBid) == 0 || len(bidResp.SeatBid[0].Bid) == 0 { + return nil, nil + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) + + for _, sb := range bidResp.SeatBid { + for i := 0; i < len(sb.Bid); i++ { + bid := sb.Bid[i] + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp), + }) + + } + } + return bidResponse, []error{} +} + +func (a *adapter) buildEndpointURL(ext *openrtb_ext.ExtImpRTBStack) string { + return strings.Replace(a.endpoint, endpointMacro, ext.Endpoint, -1) +} + +func preprocessImp( + imp *openrtb2.Imp, +) (*openrtb_ext.ExtImpRTBStack, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{Message: err.Error()} + } + + var impExt openrtb_ext.ExtImpRTBStack + if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "Wrong RTBStack bidder ext", + } + } + + imp.TagID = impExt.TagId + + // create new imp->ext without odd params + newExt := extImpRTBStack{ + TagId: impExt.TagId, + CustomParams: impExt.CustomParams, + } + + // simplify content from imp->ext->bidder to imp->ext + newImpExtForRTBStack, err := json.Marshal(newExt) + if err != nil { + return nil, &errortypes.BadInput{Message: err.Error()} + } + imp.Ext = newImpExtForRTBStack + + return &impExt, nil +} + +func getMediaTypeForImp(impID string, imps []openrtb2.Imp) openrtb_ext.BidType { + for _, imp := range imps { + if imp.ID == impID { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } else if imp.Video != nil { + return openrtb_ext.BidTypeVideo + } else if imp.Native != nil { + return openrtb_ext.BidTypeNative + } else if imp.Audio != nil { + return openrtb_ext.BidTypeAudio + } + } + } + return openrtb_ext.BidTypeBanner +} diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go new file mode 100644 index 00000000000..a55841f5183 --- /dev/null +++ b/adapters/rtbstack/rtbstack_test.go @@ -0,0 +1,19 @@ +package rtbstack + +import ( + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "testing" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderRTBStack, config.Adapter{ + Endpoint: "http://{{.Host}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "rtbstacktest", bidder) +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json new file mode 100644 index 00000000000..939c54f2526 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json @@ -0,0 +1,148 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-audio-short", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-audio-short", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-app-audio-long", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 15, + "maxduration": 60 + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-audio-long", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-audio-short", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 5, + "maxduration": 30 + }, + "tagid": "app-audio-short", + "ext": { + "tagid": "app-audio-short", + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-app-audio-long", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 15, + "maxduration": 60 + }, + "tagid": "app-audio-long", + "ext": { + "tagid": "app-audio-long" + } + } + ] + }, + "impIDs": ["imp-app-audio-short", "imp-app-audio-long"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-app-audio-short-1", + "impid": "imp-app-audio-short", + "price": 0.75, + "adm": "", + "crid": "crid-app-audio-short-1" + }, + { + "id": "bid-app-audio-long-1", + "impid": "imp-app-audio-long", + "price": 1.25, + "adm": "", + "crid": "crid-app-audio-long-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-audio-short-1", + "impid": "imp-app-audio-short", + "price": 0.75, + "adm": "", + "crid": "crid-app-audio-short-1" + }, + "type": "audio" + }, + { + "bid": { + "id": "bid-app-audio-long-1", + "impid": "imp-app-audio-long", + "price": 1.25, + "adm": "", + "crid": "crid-app-audio-long-1" + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json new file mode 100644 index 00000000000..50c095395cb --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-basic", + "banner": { + "format": [{ "w": 320, "h": 50 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-basic", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-app-large", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "app": { "bundle": "com.prebid.app" }, + "device": { "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" }, + "imp": [ + { + "id": "imp-app-basic", + "banner": { "format": [{ "w": 320, "h": 50 }] }, + "tagid": "app-basic", + "ext": { + "tagid": "app-basic", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-app-large", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "app-large", + "ext": { "tagid": "app-large" } + } + ] + }, + "impIDs": ["imp-app-basic", "imp-app-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-app-basic-1", + "impid": "imp-app-basic", + "price": 0.95, + "adm": "
App Banner 320x50
", + "crid": "crid-app-basic-1" + }, + { + "id": "bid-app-large-1", + "impid": "imp-app-large", + "price": 1.50, + "adm": "
App Banner 728x90
", + "crid": "crid-app-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-basic-1", + "impid": "imp-app-basic", + "price": 0.95, + "adm": "
App Banner 320x50
", + "crid": "crid-app-basic-1" + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-app-large-1", + "impid": "imp-app-large", + "price": 1.50, + "adm": "
App Banner 728x90
", + "crid": "crid-app-large-1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json new file mode 100644 index 00000000000..7a7f3974721 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-native-small", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":120,\"hmin\":120,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":100}}]}" + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-native-small", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-app-native-large", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-native-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-native-small", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":120,\"hmin\":120,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":100}}]}" + }, + "tagid": "app-native-small", + "ext": { + "tagid": "app-native-small", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-app-native-large", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" + }, + "tagid": "app-native-large", + "ext": { "tagid": "app-native-large" } + } + ] + }, + "impIDs": ["imp-app-native-small", "imp-app-native-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-app-native-small-1", + "impid": "imp-app-native-small", + "price": 1.5, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small App Native Ad\"}}]}}", + "crid": "crid-app-native-small-1" + }, + { + "id": "bid-app-native-large-1", + "impid": "imp-app-native-large", + "price": 2.75, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large App Native Ad\"}}]}}", + "crid": "crid-app-native-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-native-small-1", + "impid": "imp-app-native-small", + "price": 1.5, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small App Native Ad\"}}]}}", + "crid": "crid-app-native-small-1" + }, + "type": "native" + }, + { + "bid": { + "id": "bid-app-native-large-1", + "impid": "imp-app-native-large", + "price": 2.75, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large App Native Ad\"}}]}}", + "crid": "crid-app-native-large-1" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json new file mode 100644 index 00000000000..2f428f3f2db --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json @@ -0,0 +1,156 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-video-small", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4", "video/webm"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 5] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-video-small", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-app-video-large", + "video": { + "w": 1280, + "h": 720, + "mimes": ["video/mp4", "video/webm"], + "minduration": 10, + "maxduration": 60, + "protocols": [2, 5, 6] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "app-video-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-app-video-small", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4", "video/webm"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 5] + }, + "tagid": "app-video-small", + "ext": { + "tagid": "app-video-small", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-app-video-large", + "video": { + "w": 1280, + "h": 720, + "mimes": ["video/mp4", "video/webm"], + "minduration": 10, + "maxduration": 60, + "protocols": [2, 5, 6] + }, + "tagid": "app-video-large", + "ext": { "tagid": "app-video-large" } + } + ] + }, + "impIDs": ["imp-app-video-small", "imp-app-video-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-app-video-small-1", + "impid": "imp-app-video-small", + "price": 3.0, + "adm": "App Small Video Ad", + "crid": "crid-app-video-small-1" + }, + { + "id": "bid-app-video-large-1", + "impid": "imp-app-video-large", + "price": 5.5, + "adm": "App Large Video Ad", + "crid": "crid-app-video-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-video-small-1", + "impid": "imp-app-video-small", + "price": 3.0, + "adm": "App Small Video Ad", + "crid": "crid-app-video-small-1" + }, + "type": "video" + }, + { + "bid": { + "id": "bid-app-video-large-1", + "impid": "imp-app-video-large", + "price": 5.5, + "adm": "App Large Video Ad", + "crid": "crid-app-video-large-1" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json new file mode 100644 index 00000000000..8362951a24f --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json @@ -0,0 +1,177 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + }, + + { + "id": "imp-empty-custom", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "empty-custom", + "customParams": {} + } + } + }, + + { + "id": "imp-numeric-bool", + "banner": { + "format": [{ "w": 320, "h": 50 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "numeric-bool", + "customParams": { + "floor": 0.45, + "enabled": true, + "count": 3 + } + } + } + }, + + { + "id": "imp-nested-custom", + "banner": { + "format": [{ "w": 970, "h": 250 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": ["970x250", "728x90"] + } + } + } + }, + + { + "id": "imp-no-custom", + "banner": { + "format": [{ "w": 468, "h": 60 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "no-custom" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + }, + + { + "id": "imp-empty-custom", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "empty-custom", + "ext": { + "tagid": "empty-custom" + } + }, + + { + "id": "imp-numeric-bool", + "banner": { "format": [{ "w": 320, "h": 50 }] }, + "tagid": "numeric-bool", + "ext": { + "tagid": "numeric-bool", + "customParams": { + "floor": 0.45, + "enabled": true, + "count": 3 + } + } + }, + + { + "id": "imp-nested-custom", + "banner": { "format": [{ "w": 970, "h": 250 }] }, + "tagid": "nested", + "ext": { + "tagid": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": ["970x250", "728x90"] + } + } + }, + + { + "id": "imp-no-custom", + "banner": { "format": [{ "w": 468, "h": 60 }] }, + "tagid": "no-custom", + "ext": { + "tagid": "no-custom" + } + } + ] + }, + "impIDs": [ + "imp-basic", + "imp-empty-custom", + "imp-numeric-bool", + "imp-nested-custom", + "imp-no-custom" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json new file mode 100644 index 00000000000..ee36658411d --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-audio-small", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "site-audio-small", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-audio-large", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 15, + "maxduration": 60 + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "site-audio-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-audio-small", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 5, + "maxduration": 30 + }, + "tagid": "site-audio-small", + "ext": { + "tagid": "site-audio-small", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-audio-large", + "audio": { + "mimes": ["audio/mpeg", "audio/mp4"], + "minduration": 15, + "maxduration": 60 + }, + "tagid": "site-audio-large", + "ext": { "tagid": "site-audio-large" } + } + ] + }, + "impIDs": ["imp-audio-small", "imp-audio-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-site-audio-small-1", + "impid": "imp-audio-small", + "price": 0.75, + "adm": "", + "crid": "crid-site-audio-small-1" + }, + { + "id": "bid-site-audio-large-1", + "impid": "imp-audio-large", + "price": 1.25, + "adm": "", + "crid": "crid-site-audio-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-site-audio-small-1", + "impid": "imp-audio-small", + "price": 0.75, + "adm": "", + "crid": "crid-site-audio-small-1" + }, + "type": "audio" + }, + { + "bid": { + "id": "bid-site-audio-large-1", + "impid": "imp-audio-large", + "price": 1.25, + "adm": "", + "crid": "crid-site-audio-large-1" + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json new file mode 100644 index 00000000000..c216d60d6fa --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json @@ -0,0 +1,181 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-empty-custom", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "empty-custom", + "customParams": {} + } + } + }, + { + "id": "imp-nested-custom", + "banner": { + "format": [{ "w": 970, "h": 250 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": ["970x250", "728x90"] + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-empty-custom", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "empty-custom", + "ext": { + "tagid": "empty-custom" + } + }, + { + "id": "imp-nested-custom", + "banner": { "format": [{ "w": 970, "h": 250 }] }, + "tagid": "nested", + "ext": { + "tagid": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": ["970x250", "728x90"] + } + } + } + ] + }, + "impIDs": ["imp-basic", "imp-empty-custom", "imp-nested-custom"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-basic-1", + "impid": "imp-basic", + "price": 1.25, + "adm": "
Banner 728x90
", + "crid": "crid-basic-1" + }, + { + "id": "bid-empty-1", + "impid": "imp-empty-custom", + "price": 0.75, + "adm": "
Banner 300x250
", + "crid": "crid-empty-1" + }, + { + "id": "bid-nested-1", + "impid": "imp-nested-custom", + "price": 2.50, + "adm": "
Banner 970x250
", + "crid": "crid-nested-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-basic-1", + "impid": "imp-basic", + "price": 1.25, + "adm": "
Banner 728x90
", + "crid": "crid-basic-1" + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-empty-1", + "impid": "imp-empty-custom", + "price": 0.75, + "adm": "
Banner 300x250
", + "crid": "crid-empty-1" + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-nested-1", + "impid": "imp-nested-custom", + "price": 2.50, + "adm": "
Banner 970x250
", + "crid": "crid-nested-1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json new file mode 100644 index 00000000000..981d6a1ad5f --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json @@ -0,0 +1,59 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + } + ] + }, + "impIDs": [ + "imp-basic" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json new file mode 100644 index 00000000000..66a6b82b3c2 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://not-empty.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://not-empty.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + } + ] + }, + "impIDs": [ + "imp-basic" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json new file mode 100644 index 00000000000..df02faaefa1 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-site-native-small", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":120,\"hmin\":120,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":100}}]}" + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "site-native-small", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-site-native-large", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "site-native-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-site-native-small", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":120,\"hmin\":120,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":100}}]}" + }, + "tagid": "site-native-small", + "ext": { + "tagid": "site-native-small", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-site-native-large", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" + }, + "tagid": "site-native-large", + "ext": { "tagid": "site-native-large" } + } + ] + }, + "impIDs": ["imp-site-native-small", "imp-site-native-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-site-native-small-1", + "impid": "imp-site-native-small", + "price": 1.5, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small Native Ad\"}}]}}", + "crid": "crid-site-native-small-1" + }, + { + "id": "bid-site-native-large-1", + "impid": "imp-site-native-large", + "price": 2.75, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large Native Ad\"}}]}}", + "crid": "crid-site-native-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-site-native-small-1", + "impid": "imp-site-native-small", + "price": 1.5, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small Native Ad\"}}]}}", + "crid": "crid-site-native-small-1" + }, + "type": "native" + }, + { + "bid": { + "id": "bid-site-native-large-1", + "impid": "imp-site-native-large", + "price": 2.75, + "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large Native Ad\"}}]}}", + "crid": "crid-site-native-large-1" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json new file mode 100644 index 00000000000..015203326a4 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-video-small", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4", "video/webm"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 5] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "video-small", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-video-large", + "video": { + "w": 1280, + "h": 720, + "mimes": ["video/mp4", "video/webm"], + "minduration": 10, + "maxduration": 60, + "protocols": [2, 5, 6] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "video-large", + "customParams": {} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-video-small", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4", "video/webm"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 5] + }, + "tagid": "video-small", + "ext": { + "tagid": "video-small", + "customParams": { "foo": "bar" } + } + }, + { + "id": "imp-video-large", + "video": { + "w": 1280, + "h": 720, + "mimes": ["video/mp4", "video/webm"], + "minduration": 10, + "maxduration": 60, + "protocols": [2, 5, 6] + }, + "tagid": "video-large", + "ext": { "tagid": "video-large" } + } + ] + }, + "impIDs": ["imp-video-small", "imp-video-large"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-video-small-1", + "impid": "imp-video-small", + "price": 3.00, + "adm": "Small Video Ad", + "crid": "crid-video-small-1" + }, + { + "id": "bid-video-large-1", + "impid": "imp-video-large", + "price": 5.50, + "adm": "Large Video Ad", + "crid": "crid-video-large-1" + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-video-small-1", + "impid": "imp-video-small", + "price": 3.0, + "adm": "Small Video Ad", + "crid": "crid-video-small-1" + }, + "type": "video" + }, + { + "bid": { + "id": "bid-video-large-1", + "impid": "imp-video-large", + "price": 5.5, + "adm": "Large Video Ad", + "crid": "crid-video-large-1" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json new file mode 100644 index 00000000000..7fb55166c3f --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json @@ -0,0 +1,29 @@ +{ + "mockBidRequest": { + "id": "test-request-error", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-invalid", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": "invalid-json" + } + ] + }, + + "httpCalls": [], + + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json new file mode 100644 index 00000000000..6f33c73c47f --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "test-banner", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-banner", + "ext": { + "tagid": "test-banner", + "customParams": { + "foo": "bar" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "{\"id\"data.lost" + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json new file mode 100644 index 00000000000..1df1ad35fc9 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + } + ] + }, + "impIDs": ["imp-basic"] + }, + "mockResponse": { + "status": 204 + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json new file mode 100644 index 00000000000..2065c48bca5 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "basic", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "basic", + "ext": { + "tagid": "basic", + "customParams": { "foo": "bar" } + } + } + ] + }, + "impIDs": ["imp-basic"] + }, + "mockResponse": { + "status": 400 + } + } + ], + + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json new file mode 100644 index 00000000000..97f39c2be45 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-partial", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-valid", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "endpoint": "http://test.rtb-stack.com", + "tagId": "valid-tag", + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "imp-invalid", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": "invalid-json" + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://test.rtb-stack.com", + "body": { + "id": "test-request-partial", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-valid", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "valid-tag", + "ext": { + "tagid": "valid-tag", + "customParams": { + "foo": "bar" + } + } + } + ] + }, + "impIDs": ["imp-valid"] + }, + "mockResponse": { + "status": 204 + } + } + ], + + "expectedMakeRequestsErrors": [], + + "expectedBidResponses": [] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 9a2aaa0bd21..24031ebbc25 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -198,6 +198,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/rise" "github.com/prebid/prebid-server/v3/adapters/roulax" "github.com/prebid/prebid-server/v3/adapters/rtbhouse" + "github.com/prebid/prebid-server/v3/adapters/rtbstack" "github.com/prebid/prebid-server/v3/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v3/adapters/sa_lunamedia" "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" @@ -528,5 +529,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderZeroClickFraud: zeroclickfraud.Builder, openrtb_ext.BidderZetaGlobalSsp: zeta_global_ssp.Builder, openrtb_ext.BidderZmaticoo: zmaticoo.Builder, + openrtb_ext.BidderRTBStack: rtbstack.Builder, } } diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 8cd543c1f16..95b6d0b190f 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -278,6 +278,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderZeroClickFraud, BidderZetaGlobalSsp, BidderZmaticoo, + BidderRTBStack, } func GetAliasBidderToParent() map[BidderName]BidderName { @@ -651,6 +652,7 @@ const ( BidderZeroClickFraud BidderName = "zeroclickfraud" BidderZetaGlobalSsp BidderName = "zeta_global_ssp" BidderZmaticoo BidderName = "zmaticoo" + BidderRTBStack BidderName = "rtbstack" ) // CoreBidderNames returns a slice of all core bidders. diff --git a/openrtb_ext/imp_rtbstack.go b/openrtb_ext/imp_rtbstack.go new file mode 100644 index 00000000000..47411bf79b5 --- /dev/null +++ b/openrtb_ext/imp_rtbstack.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpRTBStack struct { + Endpoint string `json:"endpoint,omitempty"` + TagId string `json:"tagid,omitempty"` + CustomParams map[string]interface{} `json:"customParams,omitempty"` +} diff --git a/static/bidder-info/rtbstack.yaml b/static/bidder-info/rtbstack.yaml new file mode 100644 index 00000000000..61051fae6c4 --- /dev/null +++ b/static/bidder-info/rtbstack.yaml @@ -0,0 +1,16 @@ +endpoint: "http://{{.Host}}" +maintainer: + email: "prebid@admixer.net" +gvlVendorID: 511 +capabilities: + site: + mediaTypes: + - banner + - video + - native + + app: + mediaTypes: + - banner + - video + - native \ No newline at end of file diff --git a/static/bidder-params/rtbstack.json b/static/bidder-params/rtbstack.json new file mode 100644 index 00000000000..001be726db0 --- /dev/null +++ b/static/bidder-params/rtbstack.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RTBStack Adapter Params", + "description": "A schema which validates params accepted by the RTBStack adapter", + + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "description": "Url provided for pbs auction." + }, + "tagId": { + "type": "string", + "description": "AdUnit tag id." + }, + "customParams": { + "type": "object", + "description": "Custom values for targeting." + } + }, + + "required": ["endpoint", "tagId"] +} \ No newline at end of file From 502aaa5691258286d3860b438b737ef620e2616e Mon Sep 17 00:00:00 2001 From: Volokha Date: Tue, 10 Feb 2026 15:15:39 +0200 Subject: [PATCH 02/12] remove imp copy --- adapters/rtbstack/rtbstack.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index 5c5c5e6fdce..37a2df31498 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -48,9 +48,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E var errs []error var validImps []*impCtx - for i := range request.Imp { - imp := request.Imp[i] - + for _, imp := range request.Imp { ext, err := preprocessImp(&imp) if err != nil { errs = append(errs, err) From 60b451c1b8ed45392850893ca206982ed8fc9052 Mon Sep 17 00:00:00 2001 From: Volokha Date: Tue, 10 Feb 2026 15:42:59 +0200 Subject: [PATCH 03/12] add bidderName to appropriate place --- openrtb_ext/bidders.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 95b6d0b190f..97c2de71d38 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -216,6 +216,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderRise, BidderRoulax, BidderRTBHouse, + BidderRTBStack, BidderRubicon, BidderSeedingAlliance, BidderSeedtag, @@ -278,7 +279,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderZeroClickFraud, BidderZetaGlobalSsp, BidderZmaticoo, - BidderRTBStack, } func GetAliasBidderToParent() map[BidderName]BidderName { @@ -590,6 +590,7 @@ const ( BidderRise BidderName = "rise" BidderRoulax BidderName = "roulax" BidderRTBHouse BidderName = "rtbhouse" + BidderRTBStack BidderName = "rtbstack" BidderRubicon BidderName = "rubicon" BidderSeedingAlliance BidderName = "seedingAlliance" BidderSeedtag BidderName = "seedtag" @@ -652,7 +653,6 @@ const ( BidderZeroClickFraud BidderName = "zeroclickfraud" BidderZetaGlobalSsp BidderName = "zeta_global_ssp" BidderZmaticoo BidderName = "zmaticoo" - BidderRTBStack BidderName = "rtbstack" ) // CoreBidderNames returns a slice of all core bidders. From 5a9b3fe799baa192a8dd9e10eb470e2f1687c95e Mon Sep 17 00:00:00 2001 From: Volokha Date: Tue, 10 Feb 2026 15:44:48 +0200 Subject: [PATCH 04/12] add audio to supported media types --- static/bidder-info/rtbstack.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/rtbstack.yaml b/static/bidder-info/rtbstack.yaml index 61051fae6c4..2cf571afbd6 100644 --- a/static/bidder-info/rtbstack.yaml +++ b/static/bidder-info/rtbstack.yaml @@ -8,9 +8,10 @@ capabilities: - banner - video - native - + - audio app: mediaTypes: - banner - video - - native \ No newline at end of file + - native + - audio \ No newline at end of file From f6d7c9728c3986da8f508a80bcea00e9038741ab Mon Sep 17 00:00:00 2001 From: Volokha Date: Tue, 10 Feb 2026 15:48:04 +0200 Subject: [PATCH 05/12] order import --- adapters/rtbstack/rtbstack.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index 37a2df31498..ea5fe5641ad 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -3,14 +3,15 @@ package rtbstack import ( "encoding/json" "fmt" + "net/http" + "strings" + "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" - "net/http" - "strings" ) const endpointMacro = "http://{{.Host}}" From 11dbfcddf99742895af2f338b0fb4f6a7005ab09 Mon Sep 17 00:00:00 2001 From: Volokha Date: Fri, 13 Feb 2026 12:38:11 +0200 Subject: [PATCH 06/12] added host and query instead of endpoint for rtb-stack backend url --- adapters/rtbstack/rtbstack.go | 41 +++++++++++++++---- adapters/rtbstack/rtbstack_test.go | 2 +- .../rtbstacktest/exemplary/app-audio.json | 8 ++-- .../rtbstacktest/exemplary/app-banner.json | 8 ++-- .../rtbstacktest/exemplary/app-native.json | 8 ++-- .../rtbstacktest/exemplary/app-video.json | 8 ++-- .../exemplary/optional-params.json | 17 +++++--- .../rtbstacktest/exemplary/site-audio.json | 8 ++-- .../rtbstacktest/exemplary/site-banner.json | 11 +++-- .../exemplary/site-domain-empty-mutation.json | 5 ++- .../exemplary/site-domain-mutation.json | 5 ++- .../rtbstacktest/exemplary/site-native.json | 8 ++-- .../rtbstacktest/exemplary/site-video.json | 8 ++-- .../supplemental/bad-response.json | 5 ++- .../rtbstacktest/supplemental/status-204.json | 5 ++- .../rtbstacktest/supplemental/status-400.json | 5 ++- .../supplemental/two-imps-one-is-bad.json | 5 ++- openrtb_ext/imp_rtbstack.go | 3 +- static/bidder-info/rtbstack.yaml | 2 +- static/bidder-params/rtbstack.json | 10 +++-- 20 files changed, 116 insertions(+), 56 deletions(-) diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index ea5fe5641ad..9baa2513b65 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -5,19 +5,19 @@ import ( "fmt" "net/http" "strings" + "text/template" "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/macros" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" ) -const endpointMacro = "http://{{.Host}}" - type adapter struct { - endpoint string + endpoint *template.Template } // impCtx represents the context containing an OpenRTB impression and its corresponding RTBStack extension configuration. @@ -33,8 +33,13 @@ type extImpRTBStack struct { } func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + tpl, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + bidder := &adapter{ - endpoint: config.Endpoint, + endpoint: tpl, } return bidder, nil } @@ -71,7 +76,10 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E request.Imp = append(request.Imp, v.imp) } - endpoint := a.buildEndpointURL(validImps[0].rtbStackExt) + endpoint, err := a.buildEndpointURL(validImps[0].rtbStackExt) + if err != nil { + return nil, []error{err} + } var newRequest openrtb2.BidRequest newRequest = *request @@ -134,8 +142,27 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest return bidResponse, []error{} } -func (a *adapter) buildEndpointURL(ext *openrtb_ext.ExtImpRTBStack) string { - return strings.Replace(a.endpoint, endpointMacro, ext.Endpoint, -1) +func (a *adapter) buildEndpointURL(ext *openrtb_ext.ExtImpRTBStack) (string, error) { + // Normalize host to avoid accidental protocol prefixes and domains accidentally included + host := ext.Host + host = strings.TrimPrefix(host, "http://") + host = strings.TrimPrefix(host, "https://") + + endpointParams := macros.EndpointTemplateParams{Host: host} + baseURL, err := macros.ResolveMacros(a.endpoint, endpointParams) + if err != nil { + return "", fmt.Errorf("unable to resolve endpoint: %v", err) + } + + if ext.Query == "" { + return baseURL, nil + } + + if strings.HasPrefix(ext.Query, "/") { + return baseURL + ext.Query, nil + } + + return baseURL + "/" + ext.Query, nil } func preprocessImp( diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go index a55841f5183..7f31f0e562f 100644 --- a/adapters/rtbstack/rtbstack_test.go +++ b/adapters/rtbstack/rtbstack_test.go @@ -9,7 +9,7 @@ import ( func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderRTBStack, config.Adapter{ - Endpoint: "http://{{.Host}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "https://{{.Host}}.rtb-stack.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json index 939c54f2526..63865362e96 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json @@ -17,7 +17,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-audio-short", "customParams": { "foo": "bar" @@ -34,7 +35,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-audio-long", "customParams": {} } @@ -46,7 +48,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "app": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json index 50c095395cb..9799eafa2ec 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json @@ -15,7 +15,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-basic", "customParams": { "foo": "bar" @@ -30,7 +31,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-large", "customParams": {} } @@ -42,7 +44,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "app": { "bundle": "com.prebid.app" }, diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json index 7a7f3974721..ffb9c9ca44c 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json @@ -16,7 +16,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-native-small", "customParams": { "foo": "bar" @@ -32,7 +33,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-native-large", "customParams": {} } @@ -44,7 +46,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "app": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json index 2f428f3f2db..a050b608c44 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json @@ -20,7 +20,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-video-small", "customParams": { "foo": "bar" @@ -40,7 +41,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-video-large", "customParams": {} } @@ -52,7 +54,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "app": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json index 8362951a24f..53de9ed9732 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -29,7 +30,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "empty-custom", "customParams": {} } @@ -43,7 +45,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "numeric-bool", "customParams": { "floor": 0.45, @@ -61,7 +64,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "nested", "customParams": { "placement": { @@ -81,7 +85,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "no-custom" } } @@ -92,7 +97,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json index ee36658411d..a3b4a18c177 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json @@ -15,7 +15,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-audio-small", "customParams": { "foo": "bar" @@ -32,7 +33,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-audio-large", "customParams": {} } @@ -44,7 +46,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json index c216d60d6fa..c7c753c6cbc 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -28,7 +29,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "empty-custom", "customParams": {} } @@ -41,7 +43,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "nested", "customParams": { "placement": { @@ -59,7 +62,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json index 981d6a1ad5f..a878780e27a 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json @@ -12,7 +12,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -26,7 +27,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json index 66a6b82b3c2..61d5ac611eb 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -27,7 +28,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json index df02faaefa1..ff5f05afdb7 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json @@ -17,7 +17,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-native-small", "customParams": { "foo": "bar" @@ -33,7 +34,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-native-large", "customParams": {} } @@ -45,7 +47,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json index 015203326a4..b6baf30f0bb 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json @@ -18,7 +18,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "video-small", "customParams": { "foo": "bar" @@ -38,7 +39,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "video-large", "customParams": {} } @@ -50,7 +52,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json index 6f33c73c47f..2e2c515f583 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json @@ -14,7 +14,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "test-banner", "customParams": { "foo": "bar" @@ -28,7 +29,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json index 1df1ad35fc9..8b59c7bf474 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -27,7 +28,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json index 2065c48bca5..a46aa75c8f7 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -27,7 +28,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json index 97f39c2be45..28d53b71f87 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json @@ -13,7 +13,8 @@ }, "ext": { "bidder": { - "endpoint": "http://test.rtb-stack.com", + "host": "test", + "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "valid-tag", "customParams": { "foo": "bar" @@ -34,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://test.rtb-stack.com", + "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "body": { "id": "test-request-partial", "site": { diff --git a/openrtb_ext/imp_rtbstack.go b/openrtb_ext/imp_rtbstack.go index 47411bf79b5..78a87ebe345 100644 --- a/openrtb_ext/imp_rtbstack.go +++ b/openrtb_ext/imp_rtbstack.go @@ -1,7 +1,8 @@ package openrtb_ext type ExtImpRTBStack struct { - Endpoint string `json:"endpoint,omitempty"` + Host string `json:"host,omitempty"` + Query string `json:"query,omitempty"` TagId string `json:"tagid,omitempty"` CustomParams map[string]interface{} `json:"customParams,omitempty"` } diff --git a/static/bidder-info/rtbstack.yaml b/static/bidder-info/rtbstack.yaml index 2cf571afbd6..af397e5c872 100644 --- a/static/bidder-info/rtbstack.yaml +++ b/static/bidder-info/rtbstack.yaml @@ -1,4 +1,4 @@ -endpoint: "http://{{.Host}}" +endpoint: "https://{{.Host}}.rtb-stack.com" maintainer: email: "prebid@admixer.net" gvlVendorID: 511 diff --git a/static/bidder-params/rtbstack.json b/static/bidder-params/rtbstack.json index 001be726db0..30d1ca0cf3a 100644 --- a/static/bidder-params/rtbstack.json +++ b/static/bidder-params/rtbstack.json @@ -5,9 +5,13 @@ "type": "object", "properties": { - "endpoint": { + "host": { "type": "string", - "description": "Url provided for pbs auction." + "description": "Subdomain host used for RTBStack requests." + }, + "query": { + "type": "string", + "description": "Path and query string appended to the RTBStack endpoint." }, "tagId": { "type": "string", @@ -19,5 +23,5 @@ } }, - "required": ["endpoint", "tagId"] + "required": ["host", "query", "tagId"] } \ No newline at end of file From eb0be8ac797dc9f55eb7e9577c5ee81543c8d901 Mon Sep 17 00:00:00 2001 From: Volokha Date: Thu, 5 Mar 2026 15:24:10 +0200 Subject: [PATCH 07/12] make changes according to: https://github.com/prebid/prebid-server/pull/4685#issuecomment-3998108368 --- adapters/rtbstack/params_test.go | 57 +++++++ adapters/rtbstack/rtbstack.go | 145 +++++++++++------- adapters/rtbstack/rtbstack_test.go | 5 +- .../rtbstacktest/exemplary/app-audio.json | 22 +-- .../rtbstacktest/exemplary/app-banner.json | 22 +-- .../rtbstacktest/exemplary/app-native.json | 22 +-- .../rtbstacktest/exemplary/app-video.json | 22 +-- .../exemplary/optional-params.json | 17 +- .../rtbstacktest/exemplary/site-audio.json | 22 +-- .../rtbstacktest/exemplary/site-banner.json | 31 ++-- .../exemplary/site-domain-empty-mutation.json | 7 +- .../exemplary/site-domain-mutation.json | 5 +- .../rtbstacktest/exemplary/site-native.json | 22 +-- .../exemplary/site-region-eu.json | 94 ++++++++++++ .../exemplary/site-region-sg.json | 102 ++++++++++++ .../rtbstacktest/exemplary/site-video.json | 22 +-- .../supplemental/bad-response.json | 5 +- .../bad-route-invalid-region.json | 30 ++++ .../bad-route-missing-params.json | 30 ++++ .../rtbstacktest/supplemental/status-204.json | 5 +- .../rtbstacktest/supplemental/status-400.json | 7 +- .../supplemental/two-imps-one-is-bad.json | 5 +- openrtb_ext/imp_rtbstack.go | 5 +- static/bidder-info/rtbstack.yaml | 4 +- static/bidder-params/rtbstack.json | 11 +- 25 files changed, 535 insertions(+), 184 deletions(-) create mode 100644 adapters/rtbstack/params_test.go create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-route-invalid-region.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-route-missing-params.json diff --git a/adapters/rtbstack/params_test.go b/adapters/rtbstack/params_test.go new file mode 100644 index 00000000000..c5faf0fcd97 --- /dev/null +++ b/adapters/rtbstack/params_test.go @@ -0,0 +1,57 @@ +package rtbstack + +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.BidderRTBStack, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected rtbstack 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.BidderRTBStack, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"route":"https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145","tagId":"12345"}`, + `{"route":"https://site.eu-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2","tagId":"tag1"}`, + `{"route":"https://site.asia-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2","tagId":"tag1","customParams":{"foo":"bar"}}`, + `{"route":"https://example.us-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2","tagId":"tag1","customParams":{}}`, + `{"route":"https://example.us-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2","tagId":"tag1","customParams":{"nested":{"key":"value"}}}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"route":"https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2"}`, + `{"tagId":"12345"}`, + `{"route":"","tagId":"12345"}`, + `{"route":123,"tagId":"12345"}`, + `{"route":"https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2","tagId":123}`, +} diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index 9baa2513b65..c1ea11c26ea 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -1,9 +1,9 @@ package rtbstack import ( - "encoding/json" "fmt" "net/http" + "net/url" "strings" "text/template" @@ -54,8 +54,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E var errs []error var validImps []*impCtx - for _, imp := range request.Imp { - ext, err := preprocessImp(&imp) + for i := range request.Imp { + imp, ext, err := preprocessImp(request.Imp[i]) if err != nil { errs = append(errs, err) continue @@ -71,9 +71,9 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E return nil, errs } - request.Imp = nil + processedImps := make([]openrtb2.Imp, 0, len(validImps)) for _, v := range validImps { - request.Imp = append(request.Imp, v.imp) + processedImps = append(processedImps, v.imp) } endpoint, err := a.buildEndpointURL(validImps[0].rtbStackExt) @@ -81,16 +81,21 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E return nil, []error{err} } - var newRequest openrtb2.BidRequest - newRequest = *request + newRequest := *request + newRequest.Imp = processedImps if request.Site != nil && request.Site.Domain == "" { newSite := *request.Site - newSite.Domain = request.Site.Page + pageURL, parseErr := url.Parse(request.Site.Page) + if parseErr == nil && pageURL.Hostname() != "" { + newSite.Domain = pageURL.Hostname() + } else { + newSite.Domain = request.Site.Page + } newRequest.Site = &newSite } - reqJSON, err := json.Marshal(newRequest) + reqJSON, err := jsonutil.Marshal(newRequest) if err != nil { return nil, []error{&errortypes.BadInput{ Message: "Error parsing reqJSON object", @@ -101,21 +106,21 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") return []*adapters.RequestData{{ - Method: "POST", + Method: http.MethodPost, Uri: endpoint, Body: reqJSON, Headers: headers, - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - }}, []error{} + ImpIDs: openrtb_ext.GetImpIDs(newRequest.Imp), + }}, nil } func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if response.StatusCode == http.StatusNoContent { + if adapters.IsResponseStatusCodeNoContent(response) { return nil, nil } - if response.StatusCode != http.StatusOK { - return nil, []error{fmt.Errorf("Unexpected status code: %d", response.StatusCode)} + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} } var bidResp openrtb2.BidResponse @@ -127,90 +132,118 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest return nil, nil } - bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) + + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } + var bidErrs []error for _, sb := range bidResp.SeatBid { - for i := 0; i < len(sb.Bid); i++ { - bid := sb.Bid[i] + for i := range sb.Bid { + bidType, err := getMediaTypeForBid(sb.Bid[i]) + if err != nil { + bidErrs = append(bidErrs, err) + continue + } bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ - Bid: &bid, - BidType: getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp), + Bid: &sb.Bid[i], + BidType: bidType, }) - } } - return bidResponse, []error{} + return bidResponse, bidErrs } +var validRegions = map[string]bool{"us": true, "eu": true, "sg": true} + func (a *adapter) buildEndpointURL(ext *openrtb_ext.ExtImpRTBStack) (string, error) { - // Normalize host to avoid accidental protocol prefixes and domains accidentally included - host := ext.Host - host = strings.TrimPrefix(host, "http://") - host = strings.TrimPrefix(host, "https://") + routeURL, err := url.Parse(ext.Route) + if err != nil { + return "", &errortypes.BadInput{Message: fmt.Sprintf("invalid route URL: %v", err)} + } - endpointParams := macros.EndpointTemplateParams{Host: host} - baseURL, err := macros.ResolveMacros(a.endpoint, endpointParams) + region, err := extractRegion(routeURL.Hostname()) if err != nil { - return "", fmt.Errorf("unable to resolve endpoint: %v", err) + return "", err } - if ext.Query == "" { - return baseURL, nil + queryParams := routeURL.Query() + client := queryParams.Get("client") + endpoint := queryParams.Get("endpoint") + ssp := queryParams.Get("ssp") + + if client == "" || endpoint == "" || ssp == "" { + return "", &errortypes.BadInput{Message: "route URL must contain client, endpoint, and ssp query parameters"} } - if strings.HasPrefix(ext.Query, "/") { - return baseURL + ext.Query, nil + params := macros.EndpointTemplateParams{ + Region: region, + SspID: ssp, + ZoneID: endpoint, + PartnerId: client, } - return baseURL + "/" + ext.Query, nil + return macros.ResolveMacros(a.endpoint, params) +} + +func extractRegion(hostname string) (string, error) { + parts := strings.Split(hostname, ".") + for _, part := range parts { + if strings.HasSuffix(part, "-adx-admixer") { + region := strings.ToLower(strings.TrimSuffix(part, "-adx-admixer")) + if validRegions[region] { + return region, nil + } + } + } + return "", &errortypes.BadInput{Message: "unable to extract valid region from route URL hostname"} } func preprocessImp( - imp *openrtb2.Imp, -) (*openrtb_ext.ExtImpRTBStack, error) { + imp openrtb2.Imp, +) (openrtb2.Imp, *openrtb_ext.ExtImpRTBStack, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - return nil, &errortypes.BadInput{Message: err.Error()} + return imp, nil, &errortypes.BadInput{Message: err.Error()} } var impExt openrtb_ext.ExtImpRTBStack if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { - return nil, &errortypes.BadInput{ + return imp, nil, &errortypes.BadInput{ Message: "Wrong RTBStack bidder ext", } } imp.TagID = impExt.TagId - // create new imp->ext without odd params newExt := extImpRTBStack{ TagId: impExt.TagId, CustomParams: impExt.CustomParams, } - // simplify content from imp->ext->bidder to imp->ext - newImpExtForRTBStack, err := json.Marshal(newExt) + newImpExtForRTBStack, err := jsonutil.Marshal(newExt) if err != nil { - return nil, &errortypes.BadInput{Message: err.Error()} + return imp, nil, &errortypes.BadInput{Message: err.Error()} } imp.Ext = newImpExtForRTBStack - return &impExt, nil + return imp, &impExt, nil } -func getMediaTypeForImp(impID string, imps []openrtb2.Imp) openrtb_ext.BidType { - for _, imp := range imps { - if imp.ID == impID { - if imp.Banner != nil { - return openrtb_ext.BidTypeBanner - } else if imp.Video != nil { - return openrtb_ext.BidTypeVideo - } else if imp.Native != nil { - return openrtb_ext.BidTypeNative - } else if imp.Audio != nil { - return openrtb_ext.BidTypeAudio - } +func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported MType %d for bid %s", bid.MType, bid.ImpID), } } - return openrtb_ext.BidTypeBanner } diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go index 7f31f0e562f..9d8f74bef36 100644 --- a/adapters/rtbstack/rtbstack_test.go +++ b/adapters/rtbstack/rtbstack_test.go @@ -1,15 +1,16 @@ package rtbstack 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" - "testing" ) func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderRTBStack, config.Adapter{ - Endpoint: "https://{{.Host}}.rtb-stack.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "https://{{.Region}}-adx-admixer.rtb-stack.com/pbs?ssp={{.SspID}}&endpoint={{.ZoneID}}&client={{.PartnerId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json index 63865362e96..3b11a602314 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json @@ -17,8 +17,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-audio-short", "customParams": { "foo": "bar" @@ -35,8 +34,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-audio-long", "customParams": {} } @@ -48,7 +46,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "app": { @@ -102,14 +100,16 @@ "impid": "imp-app-audio-short", "price": 0.75, "adm": "", - "crid": "crid-app-audio-short-1" + "crid": "crid-app-audio-short-1", + "mtype": 3 }, { "id": "bid-app-audio-long-1", "impid": "imp-app-audio-long", "price": 1.25, "adm": "", - "crid": "crid-app-audio-long-1" + "crid": "crid-app-audio-long-1", + "mtype": 3 } ] } @@ -130,7 +130,8 @@ "impid": "imp-app-audio-short", "price": 0.75, "adm": "", - "crid": "crid-app-audio-short-1" + "crid": "crid-app-audio-short-1", + "mtype": 3 }, "type": "audio" }, @@ -140,11 +141,12 @@ "impid": "imp-app-audio-long", "price": 1.25, "adm": "", - "crid": "crid-app-audio-long-1" + "crid": "crid-app-audio-long-1", + "mtype": 3 }, "type": "audio" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json index 9799eafa2ec..43d60c49d20 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json @@ -15,8 +15,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-basic", "customParams": { "foo": "bar" @@ -31,8 +30,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-large", "customParams": {} } @@ -44,7 +42,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "app": { "bundle": "com.prebid.app" }, @@ -82,14 +80,16 @@ "impid": "imp-app-basic", "price": 0.95, "adm": "
App Banner 320x50
", - "crid": "crid-app-basic-1" + "crid": "crid-app-basic-1", + "mtype": 1 }, { "id": "bid-app-large-1", "impid": "imp-app-large", "price": 1.50, "adm": "
App Banner 728x90
", - "crid": "crid-app-large-1" + "crid": "crid-app-large-1", + "mtype": 1 } ] } @@ -110,7 +110,8 @@ "impid": "imp-app-basic", "price": 0.95, "adm": "
App Banner 320x50
", - "crid": "crid-app-basic-1" + "crid": "crid-app-basic-1", + "mtype": 1 }, "type": "banner" }, @@ -120,11 +121,12 @@ "impid": "imp-app-large", "price": 1.50, "adm": "
App Banner 728x90
", - "crid": "crid-app-large-1" + "crid": "crid-app-large-1", + "mtype": 1 }, "type": "banner" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json index ffb9c9ca44c..9469a3bc1dd 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json @@ -16,8 +16,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-native-small", "customParams": { "foo": "bar" @@ -33,8 +32,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-native-large", "customParams": {} } @@ -46,7 +44,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "app": { @@ -94,14 +92,16 @@ "impid": "imp-app-native-small", "price": 1.5, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small App Native Ad\"}}]}}", - "crid": "crid-app-native-small-1" + "crid": "crid-app-native-small-1", + "mtype": 4 }, { "id": "bid-app-native-large-1", "impid": "imp-app-native-large", "price": 2.75, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large App Native Ad\"}}]}}", - "crid": "crid-app-native-large-1" + "crid": "crid-app-native-large-1", + "mtype": 4 } ] } @@ -122,7 +122,8 @@ "impid": "imp-app-native-small", "price": 1.5, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small App Native Ad\"}}]}}", - "crid": "crid-app-native-small-1" + "crid": "crid-app-native-small-1", + "mtype": 4 }, "type": "native" }, @@ -132,11 +133,12 @@ "impid": "imp-app-native-large", "price": 2.75, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large App Native Ad\"}}]}}", - "crid": "crid-app-native-large-1" + "crid": "crid-app-native-large-1", + "mtype": 4 }, "type": "native" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json index a050b608c44..cd1c1ddedcd 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json @@ -20,8 +20,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-video-small", "customParams": { "foo": "bar" @@ -41,8 +40,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "app-video-large", "customParams": {} } @@ -54,7 +52,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "app": { @@ -110,14 +108,16 @@ "impid": "imp-app-video-small", "price": 3.0, "adm": "App Small Video Ad", - "crid": "crid-app-video-small-1" + "crid": "crid-app-video-small-1", + "mtype": 2 }, { "id": "bid-app-video-large-1", "impid": "imp-app-video-large", "price": 5.5, "adm": "App Large Video Ad", - "crid": "crid-app-video-large-1" + "crid": "crid-app-video-large-1", + "mtype": 2 } ] } @@ -138,7 +138,8 @@ "impid": "imp-app-video-small", "price": 3.0, "adm": "App Small Video Ad", - "crid": "crid-app-video-small-1" + "crid": "crid-app-video-small-1", + "mtype": 2 }, "type": "video" }, @@ -148,11 +149,12 @@ "impid": "imp-app-video-large", "price": 5.5, "adm": "App Large Video Ad", - "crid": "crid-app-video-large-1" + "crid": "crid-app-video-large-1", + "mtype": 2 }, "type": "video" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json index 53de9ed9732..4e4c09a643b 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -30,8 +29,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "empty-custom", "customParams": {} } @@ -45,8 +43,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "numeric-bool", "customParams": { "floor": 0.45, @@ -64,8 +61,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "nested", "customParams": { "placement": { @@ -85,8 +81,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "no-custom" } } @@ -97,7 +92,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json index a3b4a18c177..f3e917bf63b 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json @@ -15,8 +15,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-audio-small", "customParams": { "foo": "bar" @@ -33,8 +32,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-audio-large", "customParams": {} } @@ -46,7 +44,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { @@ -94,14 +92,16 @@ "impid": "imp-audio-small", "price": 0.75, "adm": "", - "crid": "crid-site-audio-small-1" + "crid": "crid-site-audio-small-1", + "mtype": 3 }, { "id": "bid-site-audio-large-1", "impid": "imp-audio-large", "price": 1.25, "adm": "", - "crid": "crid-site-audio-large-1" + "crid": "crid-site-audio-large-1", + "mtype": 3 } ] } @@ -122,7 +122,8 @@ "impid": "imp-audio-small", "price": 0.75, "adm": "", - "crid": "crid-site-audio-small-1" + "crid": "crid-site-audio-small-1", + "mtype": 3 }, "type": "audio" }, @@ -132,11 +133,12 @@ "impid": "imp-audio-large", "price": 1.25, "adm": "", - "crid": "crid-site-audio-large-1" + "crid": "crid-site-audio-large-1", + "mtype": 3 }, "type": "audio" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json index c7c753c6cbc..5152bc41757 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -29,8 +28,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "empty-custom", "customParams": {} } @@ -43,8 +41,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "nested", "customParams": { "placement": { @@ -62,7 +59,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { @@ -119,21 +116,24 @@ "impid": "imp-basic", "price": 1.25, "adm": "
Banner 728x90
", - "crid": "crid-basic-1" + "crid": "crid-basic-1", + "mtype": 1 }, { "id": "bid-empty-1", "impid": "imp-empty-custom", "price": 0.75, "adm": "
Banner 300x250
", - "crid": "crid-empty-1" + "crid": "crid-empty-1", + "mtype": 1 }, { "id": "bid-nested-1", "impid": "imp-nested-custom", "price": 2.50, "adm": "
Banner 970x250
", - "crid": "crid-nested-1" + "crid": "crid-nested-1", + "mtype": 1 } ] } @@ -154,7 +154,8 @@ "impid": "imp-basic", "price": 1.25, "adm": "
Banner 728x90
", - "crid": "crid-basic-1" + "crid": "crid-basic-1", + "mtype": 1 }, "type": "banner" }, @@ -164,7 +165,8 @@ "impid": "imp-empty-custom", "price": 0.75, "adm": "
Banner 300x250
", - "crid": "crid-empty-1" + "crid": "crid-empty-1", + "mtype": 1 }, "type": "banner" }, @@ -174,11 +176,12 @@ "impid": "imp-nested-custom", "price": 2.50, "adm": "
Banner 970x250
", - "crid": "crid-nested-1" + "crid": "crid-nested-1", + "mtype": 1 }, "type": "banner" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json index a878780e27a..c886695afdc 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json @@ -12,8 +12,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -27,12 +26,12 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { "page": "https://example.com", - "domain": "https://example.com" + "domain": "example.com" }, "imp": [ { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json index 61d5ac611eb..68d6a7a4268 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -28,7 +27,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json index ff5f05afdb7..208bc29145e 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json @@ -17,8 +17,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-native-small", "customParams": { "foo": "bar" @@ -34,8 +33,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "site-native-large", "customParams": {} } @@ -47,7 +45,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { @@ -96,14 +94,16 @@ "impid": "imp-site-native-small", "price": 1.5, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small Native Ad\"}}]}}", - "crid": "crid-site-native-small-1" + "crid": "crid-site-native-small-1", + "mtype": 4 }, { "id": "bid-site-native-large-1", "impid": "imp-site-native-large", "price": 2.75, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large Native Ad\"}}]}}", - "crid": "crid-site-native-large-1" + "crid": "crid-site-native-large-1", + "mtype": 4 } ] } @@ -124,7 +124,8 @@ "impid": "imp-site-native-small", "price": 1.5, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Small Native Ad\"}}]}}", - "crid": "crid-site-native-small-1" + "crid": "crid-site-native-small-1", + "mtype": 4 }, "type": "native" }, @@ -134,11 +135,12 @@ "impid": "imp-site-native-large", "price": 2.75, "adm": "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Large Native Ad\"}}]}}", - "crid": "crid-site-native-large-1" + "crid": "crid-site-native-large-1", + "mtype": 4 }, "type": "native" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json b/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json new file mode 100644 index 00000000000..154bc8fe78d --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json @@ -0,0 +1,94 @@ +{ + "mockBidRequest": { + "id": "test-request-eu", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-eu-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://publisher.eu-adx-admixer.rtb-stack.com/prebid?client=a1b2c3d4-e5f6-7890-abcd-ef1234567890&endpoint=500&ssp=200", + "tagId": "eu-banner", + "customParams": { + "geo": "europe" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://eu-adx-admixer.rtb-stack.com/pbs?ssp=200&endpoint=500&client=a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "body": { + "id": "test-request-eu", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-eu-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "eu-banner", + "ext": { + "tagid": "eu-banner", + "customParams": { "geo": "europe" } + } + } + ] + }, + "impIDs": ["imp-eu-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-eu", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-eu-1", + "impid": "imp-eu-banner", + "price": 1.10, + "adm": "
EU Banner 300x250
", + "crid": "crid-eu-1", + "mtype": 1 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-eu-1", + "impid": "imp-eu-banner", + "price": 1.10, + "adm": "
EU Banner 300x250
", + "crid": "crid-eu-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json b/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json new file mode 100644 index 00000000000..313d1cbcc88 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json @@ -0,0 +1,102 @@ +{ + "mockBidRequest": { + "id": "test-request-sg", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-sg-video", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4"], + "protocols": [2, 5] + }, + "ext": { + "bidder": { + "route": "https://mysite.sg-adx-admixer.rtb-stack.com/prebid?client=f9e8d7c6-b5a4-3210-fedc-ba0987654321&endpoint=777&ssp=88", + "tagId": "sg-video", + "customParams": { + "geo": "asia" + } + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://sg-adx-admixer.rtb-stack.com/pbs?ssp=88&endpoint=777&client=f9e8d7c6-b5a4-3210-fedc-ba0987654321", + "body": { + "id": "test-request-sg", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-sg-video", + "video": { + "w": 640, + "h": 360, + "mimes": ["video/mp4"], + "protocols": [2, 5] + }, + "tagid": "sg-video", + "ext": { + "tagid": "sg-video", + "customParams": { "geo": "asia" } + } + } + ] + }, + "impIDs": ["imp-sg-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-sg", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-sg-1", + "impid": "imp-sg-video", + "price": 4.50, + "adm": "SG Video Ad", + "crid": "crid-sg-1", + "mtype": 2 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-sg-1", + "impid": "imp-sg-video", + "price": 4.50, + "adm": "SG Video Ad", + "crid": "crid-sg-1", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json index b6baf30f0bb..11066febfa5 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json @@ -18,8 +18,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "video-small", "customParams": { "foo": "bar" @@ -39,8 +38,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "video-large", "customParams": {} } @@ -52,7 +50,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { @@ -106,14 +104,16 @@ "impid": "imp-video-small", "price": 3.00, "adm": "Small Video Ad", - "crid": "crid-video-small-1" + "crid": "crid-video-small-1", + "mtype": 2 }, { "id": "bid-video-large-1", "impid": "imp-video-large", "price": 5.50, "adm": "Large Video Ad", - "crid": "crid-video-large-1" + "crid": "crid-video-large-1", + "mtype": 2 } ] } @@ -134,7 +134,8 @@ "impid": "imp-video-small", "price": 3.0, "adm": "Small Video Ad", - "crid": "crid-video-small-1" + "crid": "crid-video-small-1", + "mtype": 2 }, "type": "video" }, @@ -144,11 +145,12 @@ "impid": "imp-video-large", "price": 5.5, "adm": "Large Video Ad", - "crid": "crid-video-large-1" + "crid": "crid-video-large-1", + "mtype": 2 }, "type": "video" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json index 2e2c515f583..572f73f4186 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json @@ -14,8 +14,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "test-banner", "customParams": { "foo": "bar" @@ -29,7 +28,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-route-invalid-region.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-route-invalid-region.json new file mode 100644 index 00000000000..156148b2cd9 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-route-invalid-region.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-bad-region", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-bad-region", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://publisher.xx-adx-admixer.rtb-stack.com/prebid?client=abc&endpoint=1&ssp=2", + "tagId": "test-tag" + } + } + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "unable to extract valid region from route URL hostname", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-route-missing-params.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-route-missing-params.json new file mode 100644 index 00000000000..ad6a6a463dc --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-route-missing-params.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-missing-params", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-missing-params", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://publisher.us-adx-admixer.rtb-stack.com/prebid", + "tagId": "test-tag" + } + } + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "route URL must contain client, endpoint, and ssp query parameters", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json index 8b59c7bf474..1dc79155ba0 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -28,7 +27,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json index a46aa75c8f7..fe63bf0b382 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "basic", "customParams": { "foo": "bar" @@ -28,7 +27,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", "site": { @@ -58,7 +57,7 @@ "expectedBidResponses": [], "expectedMakeBidsErrors": [ { - "value": "Unexpected status code: 400", + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", "comparison": "literal" } ] diff --git a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json index 28d53b71f87..ee4bb261567 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json @@ -13,8 +13,7 @@ }, "ext": { "bidder": { - "host": "test", - "query": "prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", "tagId": "valid-tag", "customParams": { "foo": "bar" @@ -35,7 +34,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://test.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-partial", "site": { diff --git a/openrtb_ext/imp_rtbstack.go b/openrtb_ext/imp_rtbstack.go index 78a87ebe345..d98e1b69bdd 100644 --- a/openrtb_ext/imp_rtbstack.go +++ b/openrtb_ext/imp_rtbstack.go @@ -1,8 +1,7 @@ package openrtb_ext type ExtImpRTBStack struct { - Host string `json:"host,omitempty"` - Query string `json:"query,omitempty"` - TagId string `json:"tagid,omitempty"` + Route string `json:"route"` + TagId string `json:"tagId"` CustomParams map[string]interface{} `json:"customParams,omitempty"` } diff --git a/static/bidder-info/rtbstack.yaml b/static/bidder-info/rtbstack.yaml index af397e5c872..34f02f0e973 100644 --- a/static/bidder-info/rtbstack.yaml +++ b/static/bidder-info/rtbstack.yaml @@ -1,7 +1,9 @@ -endpoint: "https://{{.Host}}.rtb-stack.com" +endpoint: "https://{{.Region}}-adx-admixer.rtb-stack.com/pbs?ssp={{.SspID}}&endpoint={{.ZoneID}}&client={{.PartnerId}}" maintainer: email: "prebid@admixer.net" gvlVendorID: 511 +openrtb: + version: "2.6" capabilities: site: mediaTypes: diff --git a/static/bidder-params/rtbstack.json b/static/bidder-params/rtbstack.json index 30d1ca0cf3a..b5b90aefd06 100644 --- a/static/bidder-params/rtbstack.json +++ b/static/bidder-params/rtbstack.json @@ -5,13 +5,10 @@ "type": "object", "properties": { - "host": { + "route": { "type": "string", - "description": "Subdomain host used for RTBStack requests." - }, - "query": { - "type": "string", - "description": "Path and query string appended to the RTBStack endpoint." + "minLength": 1, + "description": "Full route URL used to derive RTBStack endpoint (contains region, client, endpoint, ssp)." }, "tagId": { "type": "string", @@ -23,5 +20,5 @@ } }, - "required": ["host", "query", "tagId"] + "required": ["route", "tagId"] } \ No newline at end of file From 765e06444c1cfbcde8e4f8f7e7dc3d41138e7171 Mon Sep 17 00:00:00 2001 From: Volokha Date: Thu, 5 Mar 2026 15:35:16 +0200 Subject: [PATCH 08/12] add more tests --- adapters/rtbstack/rtbstack_test.go | 9 ++ .../exemplary/no-currency-in-response.json | 89 ++++++++++++++++++ .../exemplary/site-domain-fallback.json | 90 +++++++++++++++++++ .../supplemental/bad-bidder-ext.json | 27 ++++++ .../rtbstacktest/supplemental/bad-mtype.json | 84 +++++++++++++++++ .../rtbstacktest/supplemental/no-imps.json | 17 ++++ 6 files changed, 316 insertions(+) create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-bidder-ext.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/no-imps.json diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go index 9d8f74bef36..261abd41fcc 100644 --- a/adapters/rtbstack/rtbstack_test.go +++ b/adapters/rtbstack/rtbstack_test.go @@ -18,3 +18,12 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "rtbstacktest", bidder) } + +func TestBuilderInvalidTemplate(t *testing.T) { + _, err := Builder(openrtb_ext.BidderRTBStack, config.Adapter{ + Endpoint: "https://{{.Region}-bad-template"}, config.Server{}) + + if err == nil { + t.Fatal("Builder should return an error for an invalid endpoint template") + } +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json b/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json new file mode 100644 index 00000000000..1daa934ffde --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "test-tag" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "test-tag", + "ext": { + "tagid": "test-tag" + } + } + ] + }, + "impIDs": ["imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.00, + "adm": "
Banner
", + "crid": "crid-1", + "mtype": 1 + } + ] + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.00, + "adm": "
Banner
", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json new file mode 100644 index 00000000000..baeb57eb863 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "not-a-url", + "domain": "" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "test-tag" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", + "body": { + "id": "test-request-id", + "site": { + "page": "not-a-url", + "domain": "not-a-url" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "test-tag", + "ext": { + "tagid": "test-tag" + } + } + ] + }, + "impIDs": ["imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.00, + "adm": "
Banner
", + "crid": "crid-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.00, + "adm": "
Banner
", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-bidder-ext.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-bidder-ext.json new file mode 100644 index 00000000000..5d3c2f45095 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-bidder-ext.json @@ -0,0 +1,27 @@ +{ + "mockBidRequest": { + "id": "test-request-bad-bidder-ext", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-bad-ext", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": "not-an-object" + } + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "Wrong RTBStack bidder ext", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json new file mode 100644 index 00000000000..79daf0d6fd3 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "test-tag" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "test-tag", + "ext": { + "tagid": "test-tag" + } + } + ] + }, + "impIDs": ["imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.00, + "adm": "
Banner
", + "crid": "crid-1", + "mtype": 0 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported MType 0 for bid imp-banner", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/no-imps.json b/adapters/rtbstack/rtbstacktest/supplemental/no-imps.json new file mode 100644 index 00000000000..74130ada649 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/no-imps.json @@ -0,0 +1,17 @@ +{ + "mockBidRequest": { + "id": "test-request-no-imps", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "No impressions in request", + "comparison": "literal" + } + ] +} From d81cae5797859183eed180d5fc1026dae298c4cb Mon Sep 17 00:00:00 2001 From: Volokha Date: Fri, 6 Mar 2026 01:21:58 +0200 Subject: [PATCH 09/12] merged with master, upgrade to v4 --- adapters/rtbstack/rtbstack.go | 12 ++++++------ adapters/rtbstack/rtbstack_test.go | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index c1ea11c26ea..1cb3f0c55b7 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -8,12 +8,12 @@ import ( "text/template" "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/macros" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go index 261abd41fcc..a28237d4caf 100644 --- a/adapters/rtbstack/rtbstack_test.go +++ b/adapters/rtbstack/rtbstack_test.go @@ -3,9 +3,9 @@ package rtbstack 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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestJsonSamples(t *testing.T) { From 9bf074276b75aabe816fe947e1a17ca5eaf04987 Mon Sep 17 00:00:00 2001 From: Volokha Date: Fri, 6 Mar 2026 01:24:36 +0200 Subject: [PATCH 10/12] upgrade params_test.go to v4 --- adapters/rtbstack/params_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/rtbstack/params_test.go b/adapters/rtbstack/params_test.go index c5faf0fcd97..087302decb5 100644 --- a/adapters/rtbstack/params_test.go +++ b/adapters/rtbstack/params_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestValidParams(t *testing.T) { From e9fc52966e30cf0ff98fb9d7e9c94fdf103f2caa Mon Sep 17 00:00:00 2001 From: Volokha Date: Fri, 6 Mar 2026 01:33:54 +0200 Subject: [PATCH 11/12] fix comments "." --- adapters/rtbstack/rtbstack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index 1cb3f0c55b7..3b513ffc71a 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -26,7 +26,7 @@ type impCtx struct { rtbStackExt *openrtb_ext.ExtImpRTBStack } -// extImpRTBStack is used for imp->ext when sending to rtb-stack backend +// extImpRTBStack is used for imp->ext when sending to rtb-stack backend. type extImpRTBStack struct { TagId string `json:"tagid"` CustomParams map[string]interface{} `json:"customParams,omitempty"` From 00d5689923807877dfea9614372a708add65f59b Mon Sep 17 00:00:00 2001 From: Volokha Date: Fri, 24 Apr 2026 07:34:53 +0000 Subject: [PATCH 12/12] fixing issues --- adapters/rtbstack/rtbstack.go | 98 +++++--- .../rtbstacktest/exemplary/app-audio.json | 34 ++- .../rtbstacktest/exemplary/app-banner.json | 60 +++-- .../rtbstacktest/exemplary/app-native.json | 16 +- .../rtbstacktest/exemplary/app-video.json | 58 +++-- .../exemplary/multi-route-grouping.json | 235 ++++++++++++++++++ .../exemplary/multi-route-same.json | 162 ++++++++++++ .../exemplary/no-currency-in-response.json | 30 ++- .../exemplary/optional-params.json | 115 ++++++--- .../rtbstacktest/exemplary/site-audio.json | 36 ++- .../rtbstacktest/exemplary/site-banner.json | 82 ++++-- .../exemplary/site-domain-empty-mutation.json | 23 +- .../exemplary/site-domain-fallback.json | 30 ++- .../exemplary/site-domain-mutation.json | 23 +- .../rtbstacktest/exemplary/site-native.json | 16 +- .../exemplary/site-region-eu.json | 31 ++- .../exemplary/site-region-sg.json | 33 ++- .../rtbstacktest/exemplary/site-video.json | 62 +++-- .../rtbstacktest/supplemental/bad-mtype.json | 28 ++- .../supplemental/bad-response.json | 7 +- .../multi-route-partial-failure.json | 123 +++++++++ .../rtbstacktest/supplemental/status-204.json | 27 +- .../rtbstacktest/supplemental/status-400.json | 27 +- .../supplemental/two-imps-one-is-bad.json | 38 ++- 24 files changed, 1131 insertions(+), 263 deletions(-) create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/multi-route-grouping.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/multi-route-same.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json diff --git a/adapters/rtbstack/rtbstack.go b/adapters/rtbstack/rtbstack.go index 3b513ffc71a..5b5b73f0a39 100644 --- a/adapters/rtbstack/rtbstack.go +++ b/adapters/rtbstack/rtbstack.go @@ -28,7 +28,6 @@ type impCtx struct { // extImpRTBStack is used for imp->ext when sending to rtb-stack backend. type extImpRTBStack struct { - TagId string `json:"tagid"` CustomParams map[string]interface{} `json:"customParams,omitempty"` } @@ -52,7 +51,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } var errs []error - var validImps []*impCtx + impsByRoute := make(map[string][]*impCtx) + var routeOrder []string for i := range request.Imp { imp, ext, err := preprocessImp(request.Imp[i]) @@ -61,57 +61,78 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E continue } - validImps = append(validImps, &impCtx{ + ctx := &impCtx{ imp: imp, rtbStackExt: ext, - }) + } + if _, ok := impsByRoute[ext.Route]; !ok { + routeOrder = append(routeOrder, ext.Route) + } + impsByRoute[ext.Route] = append(impsByRoute[ext.Route], ctx) } - if len(validImps) == 0 { + if len(routeOrder) == 0 { return nil, errs } - processedImps := make([]openrtb2.Imp, 0, len(validImps)) - for _, v := range validImps { - processedImps = append(processedImps, v.imp) - } - - endpoint, err := a.buildEndpointURL(validImps[0].rtbStackExt) - if err != nil { - return nil, []error{err} - } - - newRequest := *request - newRequest.Imp = processedImps - + var newSite *openrtb2.Site if request.Site != nil && request.Site.Domain == "" { - newSite := *request.Site + siteCopy := *request.Site pageURL, parseErr := url.Parse(request.Site.Page) if parseErr == nil && pageURL.Hostname() != "" { - newSite.Domain = pageURL.Hostname() + siteCopy.Domain = pageURL.Hostname() } else { - newSite.Domain = request.Site.Page + siteCopy.Domain = request.Site.Page } - newRequest.Site = &newSite + newSite = &siteCopy } - reqJSON, err := jsonutil.Marshal(newRequest) - if err != nil { - return nil, []error{&errortypes.BadInput{ - Message: "Error parsing reqJSON object", - }} + requests := make([]*adapters.RequestData, 0, len(routeOrder)) + for _, route := range routeOrder { + group := impsByRoute[route] + + endpoint, err := a.buildEndpointURL(group[0].rtbStackExt) + if err != nil { + errs = append(errs, err) + continue + } + + processedImps := make([]openrtb2.Imp, 0, len(group)) + for _, v := range group { + processedImps = append(processedImps, v.imp) + } + + newRequest := *request + newRequest.Imp = processedImps + if newSite != nil { + newRequest.Site = newSite + } + + reqJSON, err := jsonutil.Marshal(newRequest) + if err != nil { + errs = append(errs, &errortypes.FailedToRequestBids{ + Message: "Error parsing reqJSON object", + }) + continue + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + requests = append(requests, &adapters.RequestData{ + Method: http.MethodPost, + Uri: endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(newRequest.Imp), + }) + } + + if len(requests) == 0 { + return nil, errs } - headers := http.Header{} - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - return []*adapters.RequestData{{ - Method: http.MethodPost, - Uri: endpoint, - Body: reqJSON, - Headers: headers, - ImpIDs: openrtb_ext.GetImpIDs(newRequest.Imp), - }}, nil + return requests, errs } func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { @@ -128,7 +149,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest return nil, []error{err} } - if len(bidResp.SeatBid) == 0 || len(bidResp.SeatBid[0].Bid) == 0 { + if len(bidResp.SeatBid) == 0 { return nil, nil } @@ -218,7 +239,6 @@ func preprocessImp( imp.TagID = impExt.TagId newExt := extImpRTBStack{ - TagId: impExt.TagId, CustomParams: impExt.CustomParams, } diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json index 3b11a602314..437343b0563 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json @@ -11,7 +11,10 @@ { "id": "imp-app-audio-short", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 5, "maxduration": 30 }, @@ -28,7 +31,10 @@ { "id": "imp-app-audio-long", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 15, "maxduration": 60 }, @@ -42,7 +48,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -59,13 +64,15 @@ { "id": "imp-app-audio-short", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 5, "maxduration": 30 }, "tagid": "app-audio-short", "ext": { - "tagid": "app-audio-short", "customParams": { "foo": "bar" } @@ -74,18 +81,22 @@ { "id": "imp-app-audio-long", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 15, "maxduration": 60 }, "tagid": "app-audio-long", - "ext": { - "tagid": "app-audio-long" - } + "ext": {} } ] }, - "impIDs": ["imp-app-audio-short", "imp-app-audio-long"] + "impIDs": [ + "imp-app-audio-short", + "imp-app-audio-long" + ] }, "mockResponse": { "status": 200, @@ -119,7 +130,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -149,4 +159,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json index 43d60c49d20..1072a3946bd 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json @@ -11,7 +11,12 @@ { "id": "imp-app-basic", "banner": { - "format": [{ "w": 320, "h": 50 }] + "format": [ + { + "w": 320, + "h": 50 + } + ] }, "ext": { "bidder": { @@ -26,7 +31,12 @@ { "id": "imp-app-large", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -38,34 +48,55 @@ } ] }, - "httpCalls": [ { "expectedRequest": { "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=145&endpoint=309&client=c4527281-5aa5-4c8e-bc53-a80bb3f99470", "body": { "id": "test-request-id", - "app": { "bundle": "com.prebid.app" }, - "device": { "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" }, + "app": { + "bundle": "com.prebid.app" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, "imp": [ { "id": "imp-app-basic", - "banner": { "format": [{ "w": 320, "h": 50 }] }, + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, "tagid": "app-basic", "ext": { - "tagid": "app-basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { "id": "imp-app-large", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "app-large", - "ext": { "tagid": "app-large" } + "ext": {} } ] }, - "impIDs": ["imp-app-basic", "imp-app-large"] + "impIDs": [ + "imp-app-basic", + "imp-app-large" + ] }, "mockResponse": { "status": 200, @@ -86,7 +117,7 @@ { "id": "bid-app-large-1", "impid": "imp-app-large", - "price": 1.50, + "price": 1.5, "adm": "
App Banner 728x90
", "crid": "crid-app-large-1", "mtype": 1 @@ -99,7 +130,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -119,7 +149,7 @@ "bid": { "id": "bid-app-large-1", "impid": "imp-app-large", - "price": 1.50, + "price": 1.5, "adm": "
App Banner 728x90
", "crid": "crid-app-large-1", "mtype": 1 @@ -129,4 +159,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json index 9469a3bc1dd..af5549ff6c4 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json @@ -40,7 +40,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -62,8 +61,9 @@ }, "tagid": "app-native-small", "ext": { - "tagid": "app-native-small", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { @@ -73,11 +73,14 @@ "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" }, "tagid": "app-native-large", - "ext": { "tagid": "app-native-large" } + "ext": {} } ] }, - "impIDs": ["imp-app-native-small", "imp-app-native-large"] + "impIDs": [ + "imp-app-native-small", + "imp-app-native-large" + ] }, "mockResponse": { "status": 200, @@ -111,7 +114,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -141,4 +143,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json index cd1c1ddedcd..c2d5b4e6bc6 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/app-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json @@ -13,10 +13,16 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 5, "maxduration": 30, - "protocols": [2, 5] + "protocols": [ + 2, + 5 + ] }, "ext": { "bidder": { @@ -33,10 +39,17 @@ "video": { "w": 1280, "h": 720, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 10, "maxduration": 60, - "protocols": [2, 5, 6] + "protocols": [ + 2, + 5, + 6 + ] }, "ext": { "bidder": { @@ -48,7 +61,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -67,15 +79,22 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 5, "maxduration": 30, - "protocols": [2, 5] + "protocols": [ + 2, + 5 + ] }, "tagid": "app-video-small", "ext": { - "tagid": "app-video-small", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { @@ -83,17 +102,27 @@ "video": { "w": 1280, "h": 720, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 10, "maxduration": 60, - "protocols": [2, 5, 6] + "protocols": [ + 2, + 5, + 6 + ] }, "tagid": "app-video-large", - "ext": { "tagid": "app-video-large" } + "ext": {} } ] }, - "impIDs": ["imp-app-video-small", "imp-app-video-large"] + "impIDs": [ + "imp-app-video-small", + "imp-app-video-large" + ] }, "mockResponse": { "status": 200, @@ -127,7 +156,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -157,4 +185,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/multi-route-grouping.json b/adapters/rtbstack/rtbstacktest/exemplary/multi-route-grouping.json new file mode 100644 index 00000000000..543b99815e1 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/multi-route-grouping.json @@ -0,0 +1,235 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-route-a-1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=client-a&endpoint=100&ssp=200", + "tagId": "tag-a-1" + } + } + }, + { + "id": "imp-route-b-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.eu-adx-admixer.rtb-stack.com/prebid?client=client-b&endpoint=300&ssp=400", + "tagId": "tag-b-1" + } + } + }, + { + "id": "imp-route-a-2", + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=client-a&endpoint=100&ssp=200", + "tagId": "tag-a-2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=200&endpoint=100&client=client-a", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-route-a-1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "tag-a-1", + "ext": {} + }, + { + "id": "imp-route-a-2", + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, + "tagid": "tag-a-2", + "ext": {} + } + ] + }, + "impIDs": [ + "imp-route-a-1", + "imp-route-a-2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-a-1", + "impid": "imp-route-a-1", + "price": 1.25, + "adm": "
A1
", + "crid": "crid-a-1", + "mtype": 1 + }, + { + "id": "bid-a-2", + "impid": "imp-route-a-2", + "price": 2.5, + "adm": "
A2
", + "crid": "crid-a-2", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://eu-adx-admixer.rtb-stack.com/pbs?ssp=400&endpoint=300&client=client-b", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-route-b-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "tag-b-1", + "ext": {} + } + ] + }, + "impIDs": [ + "imp-route-b-1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-b-1", + "impid": "imp-route-b-1", + "price": 0.75, + "adm": "
B1
", + "crid": "crid-b-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-a-1", + "impid": "imp-route-a-1", + "price": 1.25, + "adm": "
A1
", + "crid": "crid-a-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-a-2", + "impid": "imp-route-a-2", + "price": 2.5, + "adm": "
A2
", + "crid": "crid-a-2", + "mtype": 1 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-b-1", + "impid": "imp-route-b-1", + "price": 0.75, + "adm": "
B1
", + "crid": "crid-b-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/multi-route-same.json b/adapters/rtbstack/rtbstacktest/exemplary/multi-route-same.json new file mode 100644 index 00000000000..a419ed2bccc --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/multi-route-same.json @@ -0,0 +1,162 @@ +{ + "mockBidRequest": { + "id": "test-request-same-route", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-same-1", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=client-x&endpoint=500&ssp=600", + "tagId": "tag-1" + } + } + }, + { + "id": "imp-same-2", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=client-x&endpoint=500&ssp=600", + "tagId": "tag-2" + } + } + }, + { + "id": "imp-same-3", + "banner": { + "format": [{ "w": 970, "h": 250 }] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=client-x&endpoint=500&ssp=600", + "tagId": "tag-3" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=600&endpoint=500&client=client-x", + "body": { + "id": "test-request-same-route", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-same-1", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "tagid": "tag-1", + "ext": {} + }, + { + "id": "imp-same-2", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "tagid": "tag-2", + "ext": {} + }, + { + "id": "imp-same-3", + "banner": { "format": [{ "w": 970, "h": 250 }] }, + "tagid": "tag-3", + "ext": {} + } + ] + }, + "impIDs": ["imp-same-1", "imp-same-2", "imp-same-3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-same-route", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-same-1", + "impid": "imp-same-1", + "price": 1.10, + "adm": "
1
", + "crid": "crid-1", + "mtype": 1 + }, + { + "id": "bid-same-2", + "impid": "imp-same-2", + "price": 1.20, + "adm": "
2
", + "crid": "crid-2", + "mtype": 1 + }, + { + "id": "bid-same-3", + "impid": "imp-same-3", + "price": 1.30, + "adm": "
3
", + "crid": "crid-3", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-same-1", + "impid": "imp-same-1", + "price": 1.10, + "adm": "
1
", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-same-2", + "impid": "imp-same-2", + "price": 1.20, + "adm": "
2
", + "crid": "crid-2", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-same-3", + "impid": "imp-same-3", + "price": 1.30, + "adm": "
3
", + "crid": "crid-3", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json b/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json index 1daa934ffde..8e3f9494605 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json @@ -9,7 +9,12 @@ { "id": "imp-banner", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -20,7 +25,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -34,15 +38,22 @@ "imp": [ { "id": "imp-banner", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "test-tag", - "ext": { - "tagid": "test-tag" - } + "ext": {} } ] }, - "impIDs": ["imp-banner"] + "impIDs": [ + "imp-banner" + ] }, "mockResponse": { "status": 200, @@ -55,7 +66,7 @@ { "id": "bid-1", "impid": "imp-banner", - "price": 1.00, + "price": 1.0, "adm": "
Banner
", "crid": "crid-1", "mtype": 1 @@ -67,7 +78,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -76,7 +86,7 @@ "bid": { "id": "bid-1", "impid": "imp-banner", - "price": 1.00, + "price": 1.0, "adm": "
Banner
", "crid": "crid-1", "mtype": 1 diff --git a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json index 4e4c09a643b..8e3f14abfd9 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json @@ -9,7 +9,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -21,11 +26,15 @@ } } }, - { "id": "imp-empty-custom", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -35,11 +44,15 @@ } } }, - { "id": "imp-numeric-bool", "banner": { - "format": [{ "w": 320, "h": 50 }] + "format": [ + { + "w": 320, + "h": 50 + } + ] }, "ext": { "bidder": { @@ -53,11 +66,15 @@ } } }, - { "id": "imp-nested-custom", "banner": { - "format": [{ "w": 970, "h": 250 }] + "format": [ + { + "w": 970, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -68,16 +85,23 @@ "position": "top", "sticky": true }, - "sizes": ["970x250", "728x90"] + "sizes": [ + "970x250", + "728x90" + ] } } } }, - { "id": "imp-no-custom", "banner": { - "format": [{ "w": 468, "h": 60 }] + "format": [ + { + "w": 468, + "h": 60 + } + ] }, "ext": { "bidder": { @@ -88,7 +112,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -102,29 +125,46 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, - { "id": "imp-empty-custom", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "empty-custom", - "ext": { - "tagid": "empty-custom" - } + "ext": {} }, - { "id": "imp-numeric-bool", - "banner": { "format": [{ "w": 320, "h": 50 }] }, + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, "tagid": "numeric-bool", "ext": { - "tagid": "numeric-bool", "customParams": { "floor": 0.45, "enabled": true, @@ -132,30 +172,42 @@ } } }, - { "id": "imp-nested-custom", - "banner": { "format": [{ "w": 970, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, "tagid": "nested", "ext": { - "tagid": "nested", "customParams": { "placement": { "position": "top", "sticky": true }, - "sizes": ["970x250", "728x90"] + "sizes": [ + "970x250", + "728x90" + ] } } }, - { "id": "imp-no-custom", - "banner": { "format": [{ "w": 468, "h": 60 }] }, + "banner": { + "format": [ + { + "w": 468, + "h": 60 + } + ] + }, "tagid": "no-custom", - "ext": { - "tagid": "no-custom" - } + "ext": {} } ] }, @@ -172,6 +224,5 @@ } } ], - "expectedBidResponses": [] } diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json index f3e917bf63b..952d026e80b 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json @@ -9,7 +9,10 @@ { "id": "imp-audio-small", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 5, "maxduration": 30 }, @@ -26,7 +29,10 @@ { "id": "imp-audio-large", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 15, "maxduration": 60 }, @@ -40,7 +46,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -55,29 +60,39 @@ { "id": "imp-audio-small", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 5, "maxduration": 30 }, "tagid": "site-audio-small", "ext": { - "tagid": "site-audio-small", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { "id": "imp-audio-large", "audio": { - "mimes": ["audio/mpeg", "audio/mp4"], + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], "minduration": 15, "maxduration": 60 }, "tagid": "site-audio-large", - "ext": { "tagid": "site-audio-large" } + "ext": {} } ] }, - "impIDs": ["imp-audio-small", "imp-audio-large"] + "impIDs": [ + "imp-audio-small", + "imp-audio-large" + ] }, "mockResponse": { "status": 200, @@ -111,7 +126,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -141,4 +155,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json index 5152bc41757..2c0e908c6e3 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json @@ -9,7 +9,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -24,7 +29,12 @@ { "id": "imp-empty-custom", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -37,7 +47,12 @@ { "id": "imp-nested-custom", "banner": { - "format": [{ "w": 970, "h": 250 }] + "format": [ + { + "w": 970, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -48,14 +63,16 @@ "position": "top", "sticky": true }, - "sizes": ["970x250", "728x90"] + "sizes": [ + "970x250", + "728x90" + ] } } } } ] }, - "httpCalls": [ { "expectedRequest": { @@ -69,39 +86,65 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { "id": "imp-empty-custom", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "empty-custom", - "ext": { - "tagid": "empty-custom" - } + "ext": {} }, { "id": "imp-nested-custom", - "banner": { "format": [{ "w": 970, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, "tagid": "nested", "ext": { - "tagid": "nested", "customParams": { "placement": { "position": "top", "sticky": true }, - "sizes": ["970x250", "728x90"] + "sizes": [ + "970x250", + "728x90" + ] } } } ] }, - "impIDs": ["imp-basic", "imp-empty-custom", "imp-nested-custom"] + "impIDs": [ + "imp-basic", + "imp-empty-custom", + "imp-nested-custom" + ] }, "mockResponse": { "status": 200, @@ -130,7 +173,7 @@ { "id": "bid-nested-1", "impid": "imp-nested-custom", - "price": 2.50, + "price": 2.5, "adm": "
Banner 970x250
", "crid": "crid-nested-1", "mtype": 1 @@ -143,7 +186,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -174,7 +216,7 @@ "bid": { "id": "bid-nested-1", "impid": "imp-nested-custom", - "price": 2.50, + "price": 2.5, "adm": "
Banner 970x250
", "crid": "crid-nested-1", "mtype": 1 @@ -184,4 +226,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json index c886695afdc..4339d77473e 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json @@ -8,7 +8,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -22,7 +27,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -36,11 +40,19 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } } ] @@ -54,6 +66,5 @@ } } ], - "expectedBidResponses": [] } diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json index baeb57eb863..fd198b1bc29 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json @@ -9,7 +9,12 @@ { "id": "imp-banner", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -20,7 +25,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -34,15 +38,22 @@ "imp": [ { "id": "imp-banner", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "test-tag", - "ext": { - "tagid": "test-tag" - } + "ext": {} } ] }, - "impIDs": ["imp-banner"] + "impIDs": [ + "imp-banner" + ] }, "mockResponse": { "status": 200, @@ -55,7 +66,7 @@ { "id": "bid-1", "impid": "imp-banner", - "price": 1.00, + "price": 1.0, "adm": "
Banner
", "crid": "crid-1", "mtype": 1 @@ -68,7 +79,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -77,7 +87,7 @@ "bid": { "id": "bid-1", "impid": "imp-banner", - "price": 1.00, + "price": 1.0, "adm": "
Banner
", "crid": "crid-1", "mtype": 1 diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json index 68d6a7a4268..89954b712a9 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json @@ -9,7 +9,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -23,7 +28,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -37,11 +41,19 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } } ] @@ -55,6 +67,5 @@ } } ], - "expectedBidResponses": [] } diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json index 208bc29145e..9d4b0182030 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-native.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json @@ -41,7 +41,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -64,8 +63,9 @@ }, "tagid": "site-native-small", "ext": { - "tagid": "site-native-small", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { @@ -75,11 +75,14 @@ "request": "{\"ver\":\"1.0\",\"layout\":2,\"adunit\":2,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":300,\"hmin\":300,\"mimes\":[\"image/jpeg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":150}}]}" }, "tagid": "site-native-large", - "ext": { "tagid": "site-native-large" } + "ext": {} } ] }, - "impIDs": ["imp-site-native-small", "imp-site-native-large"] + "impIDs": [ + "imp-site-native-small", + "imp-site-native-large" + ] }, "mockResponse": { "status": 200, @@ -113,7 +116,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -143,4 +145,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json b/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json index 154bc8fe78d..c027397c7f2 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json @@ -9,7 +9,12 @@ { "id": "imp-eu-banner", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -23,7 +28,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -37,16 +41,26 @@ "imp": [ { "id": "imp-eu-banner", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "eu-banner", "ext": { - "tagid": "eu-banner", - "customParams": { "geo": "europe" } + "customParams": { + "geo": "europe" + } } } ] }, - "impIDs": ["imp-eu-banner"] + "impIDs": [ + "imp-eu-banner" + ] }, "mockResponse": { "status": 200, @@ -59,7 +73,7 @@ { "id": "bid-eu-1", "impid": "imp-eu-banner", - "price": 1.10, + "price": 1.1, "adm": "
EU Banner 300x250
", "crid": "crid-eu-1", "mtype": 1 @@ -72,7 +86,6 @@ } } ], - "expectedBidResponses": [ { "currency": "EUR", @@ -81,7 +94,7 @@ "bid": { "id": "bid-eu-1", "impid": "imp-eu-banner", - "price": 1.10, + "price": 1.1, "adm": "
EU Banner 300x250
", "crid": "crid-eu-1", "mtype": 1 diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json b/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json index 313d1cbcc88..7c685fe00ab 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json @@ -11,8 +11,13 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4"], - "protocols": [2, 5] + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ] }, "ext": { "bidder": { @@ -26,7 +31,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -43,18 +47,26 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4"], - "protocols": [2, 5] + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ] }, "tagid": "sg-video", "ext": { - "tagid": "sg-video", - "customParams": { "geo": "asia" } + "customParams": { + "geo": "asia" + } } } ] }, - "impIDs": ["imp-sg-video"] + "impIDs": [ + "imp-sg-video" + ] }, "mockResponse": { "status": 200, @@ -67,7 +79,7 @@ { "id": "bid-sg-1", "impid": "imp-sg-video", - "price": 4.50, + "price": 4.5, "adm": "SG Video Ad", "crid": "crid-sg-1", "mtype": 2 @@ -80,7 +92,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -89,7 +100,7 @@ "bid": { "id": "bid-sg-1", "impid": "imp-sg-video", - "price": 4.50, + "price": 4.5, "adm": "SG Video Ad", "crid": "crid-sg-1", "mtype": 2 diff --git a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json index 11066febfa5..6d3f1aeefe0 100644 --- a/adapters/rtbstack/rtbstacktest/exemplary/site-video.json +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json @@ -11,10 +11,16 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 5, "maxduration": 30, - "protocols": [2, 5] + "protocols": [ + 2, + 5 + ] }, "ext": { "bidder": { @@ -31,10 +37,17 @@ "video": { "w": 1280, "h": 720, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 10, "maxduration": 60, - "protocols": [2, 5, 6] + "protocols": [ + 2, + 5, + 6 + ] }, "ext": { "bidder": { @@ -46,7 +59,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -63,15 +75,22 @@ "video": { "w": 640, "h": 360, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 5, "maxduration": 30, - "protocols": [2, 5] + "protocols": [ + 2, + 5 + ] }, "tagid": "video-small", "ext": { - "tagid": "video-small", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } }, { @@ -79,17 +98,27 @@ "video": { "w": 1280, "h": 720, - "mimes": ["video/mp4", "video/webm"], + "mimes": [ + "video/mp4", + "video/webm" + ], "minduration": 10, "maxduration": 60, - "protocols": [2, 5, 6] + "protocols": [ + 2, + 5, + 6 + ] }, "tagid": "video-large", - "ext": { "tagid": "video-large" } + "ext": {} } ] }, - "impIDs": ["imp-video-small", "imp-video-large"] + "impIDs": [ + "imp-video-small", + "imp-video-large" + ] }, "mockResponse": { "status": 200, @@ -102,7 +131,7 @@ { "id": "bid-video-small-1", "impid": "imp-video-small", - "price": 3.00, + "price": 3.0, "adm": "Small Video Ad", "crid": "crid-video-small-1", "mtype": 2 @@ -110,7 +139,7 @@ { "id": "bid-video-large-1", "impid": "imp-video-large", - "price": 5.50, + "price": 5.5, "adm": "Large Video Ad", "crid": "crid-video-large-1", "mtype": 2 @@ -123,7 +152,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -153,4 +181,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json index 79daf0d6fd3..2b79830d114 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json @@ -9,7 +9,12 @@ { "id": "imp-banner", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": { "bidder": { @@ -20,7 +25,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -34,15 +38,22 @@ "imp": [ { "id": "imp-banner", - "banner": { "format": [{ "w": 300, "h": 250 }] }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, "tagid": "test-tag", - "ext": { - "tagid": "test-tag" - } + "ext": {} } ] }, - "impIDs": ["imp-banner"] + "impIDs": [ + "imp-banner" + ] }, "mockResponse": { "status": 200, @@ -55,7 +66,7 @@ { "id": "bid-1", "impid": "imp-banner", - "price": 1.00, + "price": 1.0, "adm": "
Banner
", "crid": "crid-1", "mtype": 0 @@ -68,7 +79,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", diff --git a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json index 572f73f4186..2901ee1359a 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json @@ -24,7 +24,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -44,7 +43,6 @@ }, "tagid": "test-banner", "ext": { - "tagid": "test-banner", "customParams": { "foo": "bar" } @@ -52,7 +50,9 @@ } ] }, - "impIDs": ["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -60,7 +60,6 @@ } } ], - "expectedMakeBidsErrors": [ { "value": "expect { or n, but found \"", diff --git a/adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json b/adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json new file mode 100644 index 00000000000..ebbf7c392d1 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "test-request-mixed-routes", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-good", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "route": "https://publisher.us-adx-admixer.rtb-stack.com/prebid?client=client-good&endpoint=10&ssp=20", + "tagId": "good-tag" + } + } + }, + { + "id": "imp-bad-region", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "route": "https://publisher.xx-adx-admixer.rtb-stack.com/prebid?client=client-bad&endpoint=99&ssp=88", + "tagId": "bad-tag" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://us-adx-admixer.rtb-stack.com/pbs?ssp=20&endpoint=10&client=client-good", + "body": { + "id": "test-request-mixed-routes", + "site": { + "page": "https://example.com", + "domain": "example.com" + }, + "imp": [ + { + "id": "imp-good", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "good-tag", + "ext": {} + } + ] + }, + "impIDs": [ + "imp-good" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-mixed-routes", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-good-1", + "impid": "imp-good", + "price": 1.0, + "adm": "
good
", + "crid": "crid-good-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-good-1", + "impid": "imp-good", + "price": 1.0, + "adm": "
good
", + "crid": "crid-good-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "unable to extract valid region from route URL hostname", + "comparison": "literal" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json index 1dc79155ba0..49d97f6c639 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json @@ -9,7 +9,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -23,7 +28,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -37,22 +41,31 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } } ] }, - "impIDs": ["imp-basic"] + "impIDs": [ + "imp-basic" + ] }, "mockResponse": { "status": 204 } } ], - "expectedBidResponses": [] } diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json index fe63bf0b382..4b8f01fd8a5 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/status-400.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json @@ -9,7 +9,12 @@ { "id": "imp-basic", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -23,7 +28,6 @@ } ] }, - "httpCalls": [ { "expectedRequest": { @@ -37,23 +41,32 @@ "imp": [ { "id": "imp-basic", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "basic", "ext": { - "tagid": "basic", - "customParams": { "foo": "bar" } + "customParams": { + "foo": "bar" + } } } ] }, - "impIDs": ["imp-basic"] + "impIDs": [ + "imp-basic" + ] }, "mockResponse": { "status": 400 } } ], - "expectedBidResponses": [], "expectedMakeBidsErrors": [ { diff --git a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json index ee4bb261567..04c1d35d984 100644 --- a/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json +++ b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json @@ -9,7 +9,12 @@ { "id": "imp-valid", "banner": { - "format": [{ "w": 728, "h": 90 }] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { @@ -24,13 +29,17 @@ { "id": "imp-invalid", "banner": { - "format": [{ "w": 300, "h": 250 }] + "format": [ + { + "w": 300, + "h": 250 + } + ] }, "ext": "invalid-json" } ] }, - "httpCalls": [ { "expectedRequest": { @@ -44,10 +53,16 @@ "imp": [ { "id": "imp-valid", - "banner": { "format": [{ "w": 728, "h": 90 }] }, + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, "tagid": "valid-tag", "ext": { - "tagid": "valid-tag", "customParams": { "foo": "bar" } @@ -55,15 +70,20 @@ } ] }, - "impIDs": ["imp-valid"] + "impIDs": [ + "imp-valid" + ] }, "mockResponse": { "status": 204 } } ], - - "expectedMakeRequestsErrors": [], - + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ], "expectedBidResponses": [] }