From 39a06898325a26ad81e224a4904fbe2147b7f4d6 Mon Sep 17 00:00:00 2001 From: Michael Stevens Date: Fri, 13 Jun 2025 20:26:40 +0100 Subject: [PATCH 001/272] Dianomi: Update user syncs to send gdpr_consent (#4345) --- static/bidder-info/dianomi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/dianomi.yaml b/static/bidder-info/dianomi.yaml index 1129e3c659..654b5a94fc 100644 --- a/static/bidder-info/dianomi.yaml +++ b/static/bidder-info/dianomi.yaml @@ -16,8 +16,8 @@ capabilities: - video userSync: iframe: - url: 'https://www-prebid.dianomi.com/prebid/usersync/index.html?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}' + url: 'https://www-prebid.dianomi.com/prebid/usersync/index.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}' userMacro: '$UID' redirect: - url: 'https://data.dianomi.com/frontend/usync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}' + url: 'https://data.dianomi.com/frontend/usync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}' userMacro: '$UID' From 705f21bc24533c1f8b1054ab8cca424b06fcb71a Mon Sep 17 00:00:00 2001 From: tomaszbmf <142428312+tomaszbmf@users.noreply.github.com> Date: Tue, 17 Jun 2025 23:01:11 +0200 Subject: [PATCH 002/272] MobileFuse: Remove tagid_src and pub_id params (#4303) * Remove tagid_src ext from MobileFuse Adapter * remove pub_id query param * removed comment * Simplify Endpoint assignment in MobileFuseAdapter --- adapters/mobilefuse/mobilefuse.go | 33 +---------- adapters/mobilefuse/mobilefuse_test.go | 10 +--- .../exemplary/multi-format.json | 5 +- .../exemplary/multi-imps-multi-format.json | 8 +-- .../mobilefusetest/exemplary/multi-imps.json | 8 +-- .../mobilefusetest/exemplary/no-bid.json | 5 +- .../exemplary/optional-params.json | 57 ------------------- .../exemplary/simple-banner.json | 5 +- .../exemplary/simple-native.json | 5 +- .../exemplary/simple-video.json | 5 +- .../mobilefusetest/exemplary/skadn.json | 6 +- .../supplemental/bad-status-code.json | 5 +- .../mobilefusetest/supplemental/no-imps.json | 3 +- .../supplemental/server-error-response.json | 5 +- adapters/mobilefuse/params_test.go | 10 +--- openrtb_ext/imp_mobilefuse.go | 4 +- static/bidder-info/mobilefuse.yaml | 2 +- static/bidder-params/mobilefuse.json | 11 +--- 18 files changed, 32 insertions(+), 155 deletions(-) delete mode 100644 adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json diff --git a/adapters/mobilefuse/mobilefuse.go b/adapters/mobilefuse/mobilefuse.go index 5670c7157c..88e562b47f 100644 --- a/adapters/mobilefuse/mobilefuse.go +++ b/adapters/mobilefuse/mobilefuse.go @@ -5,19 +5,17 @@ import ( "fmt" "net/http" "strconv" - "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" ) type MobileFuseAdapter struct { - EndpointTemplate *template.Template + Endpoint string } type ExtMf struct { @@ -34,13 +32,8 @@ type ExtSkadn struct { // Builder builds a new instance of the MobileFuse adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - template, err := template.New("endpointTemplate").Parse(config.Endpoint) - if err != nil { - return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) - } - bidder := &MobileFuseAdapter{ - EndpointTemplate: template, + Endpoint: config.Endpoint, } return bidder, nil } @@ -105,11 +98,6 @@ func (adapter *MobileFuseAdapter) makeRequest(bidRequest *openrtb2.BidRequest) ( return nil, errs } - endpoint, err := adapter.getEndpoint(mobileFuseExtension) - if err != nil { - return nil, append(errs, err) - } - validImps, err := getValidImps(bidRequest, mobileFuseExtension) if err != nil { errs = append(errs, err) @@ -129,7 +117,7 @@ func (adapter *MobileFuseAdapter) makeRequest(bidRequest *openrtb2.BidRequest) ( return &adapters.RequestData{ Method: "POST", - Uri: endpoint, + Uri: adapter.Endpoint, Body: body, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(mobileFuseBidRequest.Imp), @@ -174,21 +162,6 @@ func getMobileFuseExtensionForImp(imp *openrtb2.Imp, mobileFuseImpExtension *ope return jsonutil.Unmarshal(bidder_imp_extension.Bidder, &mobileFuseImpExtension) } -func (adapter *MobileFuseAdapter) getEndpoint(ext *openrtb_ext.ExtImpMobileFuse) (string, error) { - publisher_id := strconv.Itoa(ext.PublisherId) - - url, err := macros.ResolveMacros(adapter.EndpointTemplate, macros.EndpointTemplateParams{PublisherID: publisher_id}) - if err != nil { - return "", err - } - - if ext.TagidSrc == "ext" { - url += "&tagid_src=ext" - } - - return url, nil -} - func getValidImps(bidRequest *openrtb2.BidRequest, ext *openrtb_ext.ExtImpMobileFuse) ([]openrtb2.Imp, error) { var validImps []openrtb2.Imp diff --git a/adapters/mobilefuse/mobilefuse_test.go b/adapters/mobilefuse/mobilefuse_test.go index 41595c2256..e0a2f3dc23 100644 --- a/adapters/mobilefuse/mobilefuse_test.go +++ b/adapters/mobilefuse/mobilefuse_test.go @@ -6,12 +6,11 @@ import ( "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/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderMobileFuse, config.Adapter{ - Endpoint: "http://mfx.mobilefuse.com/openrtb?pub_id={{.PublisherID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "http://mfx.mobilefuse.com/openrtb"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) @@ -19,10 +18,3 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "mobilefusetest", bidder) } - -func TestEndpointTemplateMalformed(t *testing.T) { - _, buildErr := Builder(openrtb_ext.BidderMobileFuse, config.Adapter{ - Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - assert.Error(t, buildErr) -} diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json index 312a46277f..1fe17219c4 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-format.json @@ -25,8 +25,7 @@ }, "ext": { "bidder": { - "placement_id": 123456, - "pub_id": 1234 + "placement_id": 123456 } } } @@ -36,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1234", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json index d58eba6561..039758bd52 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json @@ -25,8 +25,7 @@ }, "ext": { "bidder": { - "placement_id": 123456, - "pub_id": 1234 + "placement_id": 123456 } } }, @@ -46,8 +45,7 @@ }, "ext": { "bidder": { - "placement_id": 234567, - "pub_id": 1234 + "placement_id": 234567 } } } @@ -56,7 +54,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1234", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json index 671c7ec1b3..4e0206f298 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json @@ -14,8 +14,7 @@ }, "ext": { "bidder": { - "placement_id": 123456, - "pub_id": 1234 + "placement_id": 123456 } } }, @@ -31,8 +30,7 @@ }, "ext": { "bidder": { - "placement_id": 234567, - "pub_id": 1234 + "placement_id": 234567 } } } @@ -42,7 +40,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1234", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json b/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json index 7ba4b900cb..f00f567ece 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/no-bid.json @@ -14,8 +14,7 @@ }, "ext": { "bidder": { - "placement_id": 999999, - "pub_id": 1111 + "placement_id": 999999 } } } @@ -25,7 +24,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1111", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json b/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json deleted file mode 100644 index 7d5d73e2d0..0000000000 --- a/adapters/mobilefuse/mobilefusetest/exemplary/optional-params.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "1", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "placement_id": 999999, - "pub_id": 1111, - "tagid_src": "ext" - } - } - } - ] - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1111&tagid_src=ext", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "1", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "999999" - } - ] - }, - "impIDs":["1"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - } - ], - - "expectedBidResponses": [] -} diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json index 3fbf9dd850..d6b70c5a28 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json @@ -14,8 +14,7 @@ }, "ext": { "bidder": { - "placement_id": 123456, - "pub_id": 1234 + "placement_id": 123456 } } } @@ -25,7 +24,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1234", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json index 5b226045c5..8a075d955a 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json @@ -10,8 +10,7 @@ }, "ext": { "bidder": { - "placement_id": 123456, - "pub_id": 1234 + "placement_id": 123456 } } } @@ -20,7 +19,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1234", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json index bfc3bcc935..71bfdaf0fe 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json @@ -17,8 +17,7 @@ }, "ext": { "bidder": { - "placement_id": 200000, - "pub_id": 2000 + "placement_id": 200000 } } } @@ -27,7 +26,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=2000", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/skadn.json b/adapters/mobilefuse/mobilefusetest/exemplary/skadn.json index 0fa29b71ae..f9e87b2f2f 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/skadn.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/skadn.json @@ -25,9 +25,7 @@ ] }, "bidder": { - "placement_id": 999999, - "pub_id": 1111, - "tagid_src": "ext" + "placement_id": 999999 } } } @@ -36,7 +34,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1111&tagid_src=ext", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json b/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json index 3de2506bff..5b173115f7 100644 --- a/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json +++ b/adapters/mobilefuse/mobilefusetest/supplemental/bad-status-code.json @@ -21,8 +21,7 @@ }, "ext": { "bidder": { - "placement_id": 999999, - "pub_id": 1111 + "placement_id": 999999 } } } @@ -32,7 +31,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1111", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json b/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json index eab96d4df6..f7453bf3a2 100644 --- a/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json +++ b/adapters/mobilefuse/mobilefusetest/supplemental/no-imps.json @@ -13,8 +13,7 @@ "id": "1", "ext": { "bidder": { - "placement_id": 999999, - "pub_id": 1111 + "placement_id": 999999 } } } diff --git a/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json b/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json index b8b8eb3f04..706b385ad6 100644 --- a/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json +++ b/adapters/mobilefuse/mobilefusetest/supplemental/server-error-response.json @@ -21,8 +21,7 @@ }, "ext": { "bidder": { - "placement_id": 999999, - "pub_id": 1111 + "placement_id": 999999 } } } @@ -32,7 +31,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://mfx.mobilefuse.com/openrtb?pub_id=1111", + "uri": "http://mfx.mobilefuse.com/openrtb", "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/mobilefuse/params_test.go b/adapters/mobilefuse/params_test.go index 363830c053..e585675457 100644 --- a/adapters/mobilefuse/params_test.go +++ b/adapters/mobilefuse/params_test.go @@ -40,15 +40,9 @@ func TestInvalidParams(test *testing.T) { } var validParams = []string{ - `{"placement_id":123,"pub_id":456}`, - `{"placement_id":123,"pub_id":456,"tagid_src":"ext"}`, - `{"placement_id":123, "pub_id":456, "tagid_src":""}`, + `{"placement_id":123}`, } var invalidParams = []string{ - `{"placement_id":123}`, - `{"pub_id":456}`, - `{"placement_id":"123","pub_id":"456"}`, - `{"placement_id":123, "placementId":123}`, - `{"tagid_src":"ext"}`, + `{"placement_id":"123"}`, } diff --git a/openrtb_ext/imp_mobilefuse.go b/openrtb_ext/imp_mobilefuse.go index 68dd3b1277..e1d347bde2 100644 --- a/openrtb_ext/imp_mobilefuse.go +++ b/openrtb_ext/imp_mobilefuse.go @@ -2,7 +2,5 @@ package openrtb_ext // ExtImpMobileFuse defines the contract for bidrequest.imp[i].ext.prebid.bidder.mobilefuse type ExtImpMobileFuse struct { - PlacementId int `json:"placement_id"` - PublisherId int `json:"pub_id"` - TagidSrc string `json:"tagid_src"` + PlacementId int `json:"placement_id"` } diff --git a/static/bidder-info/mobilefuse.yaml b/static/bidder-info/mobilefuse.yaml index 6bd152e481..14e488d077 100644 --- a/static/bidder-info/mobilefuse.yaml +++ b/static/bidder-info/mobilefuse.yaml @@ -1,4 +1,4 @@ -endpoint: "http://mfx.mobilefuse.com/openrtb?pub_id={{.PublisherID}}" +endpoint: "http://mfx.mobilefuse.com/openrtb" # This bidder does not operate globally. Please consider setting "disabled: true" outside of the following regions: geoscope: - USA diff --git a/static/bidder-params/mobilefuse.json b/static/bidder-params/mobilefuse.json index 15f1714807..99928f860c 100644 --- a/static/bidder-params/mobilefuse.json +++ b/static/bidder-params/mobilefuse.json @@ -7,18 +7,9 @@ "placement_id": { "type": "integer", "description": "An ID which identifies this specific inventory placement" - }, - "pub_id": { - "type": "integer", - "description": "An ID which identifies the publisher selling the inventory." - }, - "tagid_src": { - "type": "string", - "description": "ext if passing publisher's ids, empty if passing MobileFuse IDs in placement_id field. Defaults to empty" } }, "required": [ - "placement_id", - "pub_id" + "placement_id" ] } \ No newline at end of file From 2ca5bb576b88ebbe1d3c5a1f5eecfb36ff4a52f7 Mon Sep 17 00:00:00 2001 From: FlatAds <83808812+flatads@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:13:19 +0800 Subject: [PATCH 003/272] New Adapter: Flatads (#4243) Co-authored-by: wuzhijian --- adapters/flatads/flatads.go | 157 +++++++++++++ adapters/flatads/flatads_test.go | 29 +++ .../flatads/flatadstest/exemplary/banner.json | 122 ++++++++++ .../flatadstest/exemplary/headers_ipv4.json | 124 ++++++++++ .../flatadstest/exemplary/headers_ipv6.json | 123 ++++++++++ .../flatadstest/exemplary/multiple-imps.json | 213 ++++++++++++++++++ .../flatads/flatadstest/exemplary/native.json | 114 ++++++++++ .../exemplary/optional-params.json | 126 +++++++++++ .../flatads/flatadstest/exemplary/video.json | 120 ++++++++++ .../flatadstest/supplemental/bad-request.json | 92 ++++++++ .../supplemental/invalid-bid-type.json | 117 ++++++++++ .../supplemental/invalid-imp-ext-bidder.json | 33 +++ .../supplemental/invalid-imp-ext.json | 31 +++ .../multiple-imps-with-error.json | 145 ++++++++++++ .../response-200-without-body.json | 90 ++++++++ .../supplemental/response-204.json | 85 +++++++ .../supplemental/server-error.json | 73 ++++++ adapters/flatads/params_test.go | 51 +++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_flatads.go | 6 + static/bidder-info/flatads.yaml | 17 ++ static/bidder-params/flatads.json | 22 ++ 23 files changed, 1894 insertions(+) create mode 100644 adapters/flatads/flatads.go create mode 100644 adapters/flatads/flatads_test.go create mode 100644 adapters/flatads/flatadstest/exemplary/banner.json create mode 100644 adapters/flatads/flatadstest/exemplary/headers_ipv4.json create mode 100644 adapters/flatads/flatadstest/exemplary/headers_ipv6.json create mode 100644 adapters/flatads/flatadstest/exemplary/multiple-imps.json create mode 100644 adapters/flatads/flatadstest/exemplary/native.json create mode 100644 adapters/flatads/flatadstest/exemplary/optional-params.json create mode 100644 adapters/flatads/flatadstest/exemplary/video.json create mode 100644 adapters/flatads/flatadstest/supplemental/bad-request.json create mode 100644 adapters/flatads/flatadstest/supplemental/invalid-bid-type.json create mode 100644 adapters/flatads/flatadstest/supplemental/invalid-imp-ext-bidder.json create mode 100644 adapters/flatads/flatadstest/supplemental/invalid-imp-ext.json create mode 100644 adapters/flatads/flatadstest/supplemental/multiple-imps-with-error.json create mode 100644 adapters/flatads/flatadstest/supplemental/response-200-without-body.json create mode 100644 adapters/flatads/flatadstest/supplemental/response-204.json create mode 100644 adapters/flatads/flatadstest/supplemental/server-error.json create mode 100644 adapters/flatads/params_test.go create mode 100644 openrtb_ext/imp_flatads.go create mode 100644 static/bidder-info/flatads.yaml create mode 100644 static/bidder-params/flatads.json diff --git a/adapters/flatads/flatads.go b/adapters/flatads/flatads.go new file mode 100644 index 0000000000..0bf0b979e7 --- /dev/null +++ b/adapters/flatads/flatads.go @@ -0,0 +1,157 @@ +package flatads + +import ( + "fmt" + "net/http" + "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" +) + +type adapter struct { + endpoint *template.Template +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint template: %v", err) + } + + bidder := &adapter{ + endpoint: endpointTemplate, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var requests []*adapters.RequestData + var errs []error + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + if request.Device != nil { + if len(request.Device.UA) > 0 { + headers.Add("User-Agent", request.Device.UA) + } + + if len(request.Device.IPv6) > 0 { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.IP) > 0 { + headers.Add("X-Forwarded-For", request.Device.IP) + } + } + for _, imp := range request.Imp { + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{imp} + + endpoint, err := a.buildEndpointFromRequest(&imp) + if err != nil { + errs = append(errs, err) + continue + } + + requestJSON, err := jsonutil.Marshal(requestCopy) + if err != nil { + errs = append(errs, err) + continue + } + + r := &adapters.RequestData{ + Method: http.MethodPost, + Body: requestJSON, + Uri: endpoint, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), + } + + requests = append(requests, r) + } + + return requests, errs +} + +func (a *adapter) buildEndpointFromRequest(imp *openrtb2.Imp) (string, error) { + var impExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &impExt); err != nil { + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to deserialize bidder impression extension: %v", err), + } + } + + var flatadsExt openrtb_ext.ImpExtFlatads + if err := jsonutil.Unmarshal(impExt.Bidder, &flatadsExt); err != nil { + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to deserialize Flatads extension: %v", err), + } + } + + endpointParams := macros.EndpointTemplateParams{ + TokenID: flatadsExt.Token, + PublisherID: flatadsExt.PublisherId, + } + + return macros.ResolveMacros(a.endpoint, endpointParams) +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + err := adapters.CheckResponseStatusCodeForErrors(responseData) + if err != nil { + return nil, []error{err} + } + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if len(response.Cur) != 0 { + bidResponse.Currency = response.Cur + } + + var errors []error + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidMediaType, err := getMediaTypeForBid(seatBid.Bid[i].ImpID, request.Imp) + if err != nil { + errors = append(errors, err) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidMediaType, + }) + } + } + return bidResponse, errors +} + +func getMediaTypeForBid(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { + for _, imp := range imps { + if imp.ID == impID { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner, nil + } else if imp.Video != nil { + return openrtb_ext.BidTypeVideo, nil + } else if imp.Native != nil { + return openrtb_ext.BidTypeNative, nil + } + } + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("The impression with ID %s is not present into the request", impID), + } +} diff --git a/adapters/flatads/flatads_test.go b/adapters/flatads/flatads_test.go new file mode 100644 index 0000000000..b3b3cf33f7 --- /dev/null +++ b/adapters/flatads/flatads_test.go @@ -0,0 +1,29 @@ +package flatads + +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/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderFlatads, config.Adapter{ + Endpoint: "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id={{.PublisherID}}&x-net-token={{.TokenID}}"}, + config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "flatadstest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderFlatads, config.Adapter{ + Endpoint: "x-net-id={{PublisherID}}&x-net-token={{TokenID}}"}, config.Server{}) + + assert.Error(t, buildErr) +} diff --git a/adapters/flatads/flatadstest/exemplary/banner.json b/adapters/flatads/flatadstest/exemplary/banner.json new file mode 100644 index 0000000000..5cdf66ac0d --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/banner.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/exemplary/headers_ipv4.json b/adapters/flatads/flatadstest/exemplary/headers_ipv4.json new file mode 100644 index 0000000000..ac997f9657 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/headers_ipv4.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/exemplary/headers_ipv6.json b/adapters/flatads/flatadstest/exemplary/headers_ipv6.json new file mode 100644 index 0000000000..2d12280c73 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/headers_ipv6.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "2607:fb90:f27:4512:d800:cb23:a603:e245" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file diff --git a/adapters/flatads/flatadstest/exemplary/multiple-imps.json b/adapters/flatads/flatadstest/exemplary/multiple-imps.json new file mode 100644 index 0000000000..282037b844 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/multiple-imps.json @@ -0,0 +1,213 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + }, + { + "id": "test-imp-id-banner2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "22223333", + "publisherId": "2222" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=2222&x-net-token=22223333", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "22223333", + "publisherId": "2222" + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801", + "impid": "test-imp-id-banner2", + "price": 0.5, + "adm": "some-test-ad-banner2", + "crid": "crid_11", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801", + "impid": "test-imp-id-banner2", + "price": 0.5, + "adm": "some-test-ad-banner2", + "crid": "crid_11", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/exemplary/native.json b/adapters/flatads/flatadstest/exemplary/native.json new file mode 100644 index 0000000000..c4b6768733 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/native.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "id": "test-request-id-native", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-native", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-native", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-native", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-native" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-native", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-native", + "price": 0.5, + "adm": "some-test-ad-native", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-native", + "price": 0.5, + "adm": "some-test-ad-native", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/exemplary/optional-params.json b/adapters/flatads/flatadstest/exemplary/optional-params.json new file mode 100644 index 0000000000..20441dadf4 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/optional-params.json @@ -0,0 +1,126 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111", + "bidFloor": 0.1, + "isTest": false + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111", + "bidFloor": 0.1, + "isTest": false + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/exemplary/video.json b/adapters/flatads/flatadstest/exemplary/video.json new file mode 100644 index 0000000000..dc2f1bf532 --- /dev/null +++ b/adapters/flatads/flatadstest/exemplary/video.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-video-id", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-video-id", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-video-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-test-video-id", + "seatbid": [ + { + "seat": "test-seat", + "bid": [ + { + "id": "5dce6055-a93c-1fd0-8c29-14afc3e510fd", + "impid": "test-video-id", + "price": 0.1529, + "nurl": "test-win", + "adm": "test-video", + "adid": "92-288", + "adomain": ["advertiserdomain.com"], + "crid": "288", + "w": 300, + "h": 250 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "5dce6055-a93c-1fd0-8c29-14afc3e510fd", + "impid": "test-video-id", + "price": 0.1529, + "nurl": "test-win", + "adm": "test-video", + "adid": "92-288", + "adomain": ["advertiserdomain.com"], + "crid": "288", + "w": 300, + "h": 250 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/supplemental/bad-request.json b/adapters/flatads/flatadstest/supplemental/bad-request.json new file mode 100644 index 0000000000..25be9ed246 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/bad-request.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "headers": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/flatads/flatadstest/supplemental/invalid-bid-type.json b/adapters/flatads/flatadstest/supplemental/invalid-bid-type.json new file mode 100644 index 0000000000..87331a1f72 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/invalid-bid-type.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-invalid", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "The impression with ID test-imp-id-invalid is not present into the request", + "comparison": "literal" + } + ] +} diff --git a/adapters/flatads/flatadstest/supplemental/invalid-imp-ext-bidder.json b/adapters/flatads/flatadstest/supplemental/invalid-imp-ext-bidder.json new file mode 100644 index 0000000000..3d210a3452 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/invalid-imp-ext-bidder.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": "" + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Failed to deserialize Flatads extension: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/flatads/flatadstest/supplemental/invalid-imp-ext.json b/adapters/flatads/flatadstest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..4790fc34d1 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/invalid-imp-ext.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": "" + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Failed to deserialize bidder impression extension: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/flatads/flatadstest/supplemental/multiple-imps-with-error.json b/adapters/flatads/flatadstest/supplemental/multiple-imps-with-error.json new file mode 100644 index 0000000000..908c06df7c --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/multiple-imps-with-error.json @@ -0,0 +1,145 @@ +{ + "mockBidRequest": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + }, + { + "id": "test-imp-id-banner2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": {}, + "publisherId": "1111" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id-banner", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id-banner", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-banner", + "seatbid": [ + { + "seat": "flatads", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Failed to deserialize Flatads extension: cannot unmarshal openrtb_ext.ImpExtFlatads.Token: expects \" or n, but found {", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id-banner", + "price": 0.5, + "adm": "some-test-ad-banner", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/flatads/flatadstest/supplemental/response-200-without-body.json b/adapters/flatads/flatadstest/supplemental/response-200-without-body.json new file mode 100644 index 0000000000..2ee9b421d1 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/response-200-without-body.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ] +} \ No newline at end of file diff --git a/adapters/flatads/flatadstest/supplemental/response-204.json b/adapters/flatads/flatadstest/supplemental/response-204.json new file mode 100644 index 0000000000..f93bdeedc6 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/response-204.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/flatads/flatadstest/supplemental/server-error.json b/adapters/flatads/flatadstest/supplemental/server-error.json new file mode 100644 index 0000000000..0d9d3cebb0 --- /dev/null +++ b/adapters/flatads/flatadstest/supplemental/server-error.json @@ -0,0 +1,73 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://test.endpoint.com/api/rtbs/adx/rtb?x-net-id=1111&x-net-token=66668888", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "token": "66668888", + "publisherId": "1111" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 500, + "headers": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/flatads/params_test.go b/adapters/flatads/params_test.go new file mode 100644 index 0000000000..c58546399b --- /dev/null +++ b/adapters/flatads/params_test.go @@ -0,0 +1,51 @@ +package flatads + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderFlatads, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderFlatads, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{ "token": "66668888", + "publisherId": "1111" + }`, + `{"token": "66668888", "publisherId": "1111"}`, +} + +var invalidParams = []string{ + `{}`, + `{"token": 66668888, "networkId":1111}`, + `{"token": "66668888"", "networkId":1111}`, + `{"token": 66668888, "networkId":"1111""}`, + `{"token": "", "publisherId": "1111"}`, + `{"token": "66668888", "publisherId": ""}`, + `{"token": "", "publisherId": ""}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 78671073de..b7fc856d40 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -101,6 +101,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/epom" "github.com/prebid/prebid-server/v3/adapters/escalax" "github.com/prebid/prebid-server/v3/adapters/feedad" + "github.com/prebid/prebid-server/v3/adapters/flatads" "github.com/prebid/prebid-server/v3/adapters/flipp" "github.com/prebid/prebid-server/v3/adapters/freewheelssp" "github.com/prebid/prebid-server/v3/adapters/frvradn" @@ -355,6 +356,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEscalax: escalax.Builder, openrtb_ext.BidderEVolution: evolution.Builder, openrtb_ext.BidderFeedAd: feedad.Builder, + openrtb_ext.BidderFlatads: flatads.Builder, openrtb_ext.BidderFlipp: flipp.Builder, openrtb_ext.BidderFreewheelSSP: freewheelssp.Builder, openrtb_ext.BidderFWSSP: fwssp.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index a2e39fdd5e..b0ec96f751 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -118,6 +118,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderEscalax, BidderEVolution, BidderFeedAd, + BidderFlatads, BidderFlipp, BidderFreewheelSSP, BidderFWSSP, @@ -478,6 +479,7 @@ const ( BidderEscalax BidderName = "escalax" BidderEVolution BidderName = "e_volution" BidderFeedAd BidderName = "feedad" + BidderFlatads BidderName = "flatads" BidderFlipp BidderName = "flipp" BidderFreewheelSSP BidderName = "freewheelssp" BidderFWSSP BidderName = "fwssp" diff --git a/openrtb_ext/imp_flatads.go b/openrtb_ext/imp_flatads.go new file mode 100644 index 0000000000..331190a78c --- /dev/null +++ b/openrtb_ext/imp_flatads.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtFlatads struct { + Token string `json:"token"` + PublisherId string `json:"publisherId"` +} diff --git a/static/bidder-info/flatads.yaml b/static/bidder-info/flatads.yaml new file mode 100644 index 0000000000..5e1e7c47cc --- /dev/null +++ b/static/bidder-info/flatads.yaml @@ -0,0 +1,17 @@ +endpoint: "https://bid.rtbshark.com/api/rtbs/adx/rtb?x-net-id={{.PublisherID}}&x-net-token={{.TokenID}}" +endpointCompression: gzip +maintainer: + email: "adxbusiness@flat-ads.com" +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/flatads.json b/static/bidder-params/flatads.json new file mode 100644 index 0000000000..5f3eb8738a --- /dev/null +++ b/static/bidder-params/flatads.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Flatads Adapter Params", + "description": "A schema which validates params accepted by the Flatads adapter", + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Token of the publisher", + "minLength": 1 + }, + "publisherId": { + "type": "string", + "description": "Flatads Publisher Id", + "minLength": 1 + } + }, + "required": [ + "token", + "publisherId" + ] +} \ No newline at end of file From d7aa6185fd63a57520c3c5db52c6346cb9c805c4 Mon Sep 17 00:00:00 2001 From: Anton Babak <76536883+AntoxaAntoxic@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:23:15 +0200 Subject: [PATCH 004/272] Rubicon: Add bid meta seat (#4348) --- adapters/rubicon/rubicon.go | 13 ++++----- adapters/rubicon/rubicon_test.go | 27 +++++++++++++++++++ .../exemplary/25-26-transition-period.json | 5 ++-- .../rubicontest/exemplary/app-imp-fpd.json | 7 +++-- .../exemplary/bidonmultiformat.json | 27 ++++++++++++------- .../exemplary/flexible-schema.json | 7 +++-- .../exemplary/hardcode-secure.json | 5 ++-- .../exemplary/non-bidonmultiformat.json | 13 ++++++--- .../rubicontest/exemplary/simple-banner.json | 5 ++-- .../rubicontest/exemplary/simple-native.json | 5 ++-- .../rubicontest/exemplary/simple-video.json | 5 ++-- .../rubicontest/exemplary/site-imp-fpd.json | 19 +++++++------ .../rubicontest/exemplary/user-fpd.json | 19 +++++++------ .../supplemental/no-site-content-data.json | 25 ++++++++--------- .../supplemental/no-site-content.json | 19 +++++++------ openrtb_ext/bid.go | 1 + 16 files changed, 133 insertions(+), 69 deletions(-) diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go index 91fac7a43f..2a433464eb 100644 --- a/adapters/rubicon/rubicon.go +++ b/adapters/rubicon/rubicon.go @@ -976,7 +976,7 @@ func (a *RubiconAdapter) MakeBids(internalRequest *openrtb2.BidRequest, external for i := 0; i < len(sb.Bid); i++ { bid := sb.Bid[i] - updatedBidExt := updateBidExtWithMetaNetworkId(bid, buyer) + updatedBidExt := updateBidExtWithMeta(bid, buyer, sb.Seat) if updatedBidExt != nil { bid.Ext = updatedBidExt } @@ -1067,8 +1067,8 @@ func cmpOverrideFromBidRequest(bidRequest *openrtb2.BidRequest) float64 { return bidRequestExt.Prebid.Bidders.Rubicon.Debug.CpmOverride } -func updateBidExtWithMetaNetworkId(bid rubiconBid, buyer int) json.RawMessage { - if buyer <= 0 { +func updateBidExtWithMeta(bid rubiconBid, buyer int, seat string) json.RawMessage { + if buyer <= 0 && seat == "" { return nil } var bidExt *extPrebid @@ -1082,14 +1082,15 @@ func updateBidExtWithMetaNetworkId(bid rubiconBid, buyer int) json.RawMessage { if bidExt.Prebid != nil { if bidExt.Prebid.Meta != nil { bidExt.Prebid.Meta.NetworkID = buyer + bidExt.Prebid.Meta.Seat = seat } else { - bidExt.Prebid.Meta = &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer} + bidExt.Prebid.Meta = &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer, Seat: seat} } } else { - bidExt.Prebid = &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer}} + bidExt.Prebid = &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer, Seat: seat}} } } else { - bidExt = &extPrebid{Prebid: &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer}}} + bidExt = &extPrebid{Prebid: &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: buyer, Seat: seat}}} } marshalledExt, err := json.Marshal(&bidExt) diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go index 7ab62370eb..3e26e2db12 100644 --- a/adapters/rubicon/rubicon_test.go +++ b/adapters/rubicon/rubicon_test.go @@ -993,6 +993,33 @@ func TestOpenRTBResponseSettingOfNetworkId(t *testing.T) { } } +func TestUpdateBidExtWithMeta_OnlySeatSet(t *testing.T) { + bid := rubiconBid{ + Bid: openrtb2.Bid{ + Ext: nil, + }, + AdmNative: nil, + } + seat := "test-seat" + buyer := 0 + + ext := updateBidExtWithMeta(bid, buyer, seat) + assert.NotNil(t, ext, "Expected non-nil ext when seat is set") + + var extPrebidWrapper struct { + Prebid struct { + Meta struct { + Seat string `json:"seat"` + NetworkID *int `json:"networkId,omitempty"` + } `json:"meta"` + } `json:"prebid"` + } + err := json.Unmarshal(ext, &extPrebidWrapper) + assert.NoError(t, err, "Unmarshal should succeed") + assert.Equal(t, seat, extPrebidWrapper.Prebid.Meta.Seat, "Seat should be set") + assert.Zero(t, extPrebidWrapper.Prebid.Meta.NetworkID, "NetworkID should be omitted or zero") +} + func TestOpenRTBResponseBidExtPrebidMetaPassthrough(t *testing.T) { request := &openrtb2.BidRequest{ Imp: []openrtb2.Imp{{ diff --git a/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json b/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json index 63eb23e5ff..ce279fffc8 100644 --- a/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json +++ b/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json @@ -414,7 +414,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -438,7 +438,8 @@ "ext": { "prebid": { "meta": { - "networkId": 123 + "networkId": 123, + "seat": "rubicon" }, "type": "banner" } diff --git a/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json index c90e463bab..b638284d8c 100644 --- a/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json @@ -374,7 +374,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -397,7 +397,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, diff --git a/adapters/rubicon/rubicontest/exemplary/bidonmultiformat.json b/adapters/rubicon/rubicontest/exemplary/bidonmultiformat.json index dc68d23f59..191828a492 100644 --- a/adapters/rubicon/rubicontest/exemplary/bidonmultiformat.json +++ b/adapters/rubicon/rubicontest/exemplary/bidonmultiformat.json @@ -115,7 +115,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -139,7 +141,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -185,8 +187,7 @@ "video": { "placement": 3, "ext": { - "rp": { - } + "rp": {} }, "mimes": [ "video/mp4" @@ -218,7 +219,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -242,7 +245,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -265,7 +268,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "banner" + "type": "banner", + "meta": { + "seat": "rubicon" + } } } }, @@ -287,7 +293,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, @@ -296,4 +305,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/adapters/rubicon/rubicontest/exemplary/flexible-schema.json b/adapters/rubicon/rubicontest/exemplary/flexible-schema.json index 800231ae53..ea7aab8f96 100644 --- a/adapters/rubicon/rubicontest/exemplary/flexible-schema.json +++ b/adapters/rubicon/rubicontest/exemplary/flexible-schema.json @@ -376,7 +376,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -399,7 +399,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, diff --git a/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json b/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json index 2040933b48..af29f8a8cd 100644 --- a/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json +++ b/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json @@ -361,7 +361,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -385,7 +385,8 @@ "ext": { "prebid": { "meta": { - "networkId": 123 + "networkId": 123, + "seat": "rubicon" }, "type": "video" } diff --git a/adapters/rubicon/rubicontest/exemplary/non-bidonmultiformat.json b/adapters/rubicon/rubicontest/exemplary/non-bidonmultiformat.json index 534f8aae79..327aa34f0d 100644 --- a/adapters/rubicon/rubicontest/exemplary/non-bidonmultiformat.json +++ b/adapters/rubicon/rubicontest/exemplary/non-bidonmultiformat.json @@ -114,7 +114,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -138,7 +140,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -161,7 +163,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "banner" + "type": "banner", + "meta": { + "seat": "rubicon" + } } } }, @@ -170,4 +175,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/adapters/rubicon/rubicontest/exemplary/simple-banner.json b/adapters/rubicon/rubicontest/exemplary/simple-banner.json index 2f095ab5b3..7a34db5e8d 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-banner.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-banner.json @@ -371,7 +371,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -395,7 +395,8 @@ "ext": { "prebid": { "meta": { - "networkId": 123 + "networkId": 123, + "seat": "rubicon" }, "type": "banner" } diff --git a/adapters/rubicon/rubicontest/exemplary/simple-native.json b/adapters/rubicon/rubicontest/exemplary/simple-native.json index 576faecbee..f3341c213c 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-native.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-native.json @@ -348,7 +348,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -372,7 +372,8 @@ "ext": { "prebid": { "meta": { - "networkId": 123 + "networkId": 123, + "seat": "rubicon" }, "type": "native" } diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json index ccdfab1699..3686d87a2c 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-video.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json @@ -362,7 +362,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -386,7 +386,8 @@ "ext": { "prebid": { "meta": { - "networkId": 123 + "networkId": 123, + "seat": "rubicon" }, "type": "video" } diff --git a/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json index 9a8468ce15..473554c9a3 100644 --- a/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json @@ -206,8 +206,7 @@ "dataAttr2": "dataVal2" }, "bidder": { - "video": { - }, + "video": {}, "accountId": 1001, "siteId": 113932, "zoneId": 535510 @@ -414,8 +413,7 @@ "video": { "placement": 3, "ext": { - "rp": { - } + "rp": {} }, "mimes": [ "video/mp4" @@ -473,7 +471,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -497,7 +497,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -520,7 +520,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, @@ -529,4 +532,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/adapters/rubicon/rubicontest/exemplary/user-fpd.json b/adapters/rubicon/rubicontest/exemplary/user-fpd.json index a03234d48d..3947ca28b7 100644 --- a/adapters/rubicon/rubicontest/exemplary/user-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/user-fpd.json @@ -115,8 +115,7 @@ "dataAttr2": "dataVal2" }, "bidder": { - "video": { - }, + "video": {}, "accountId": 1001, "siteId": 113932, "zoneId": 535510 @@ -243,8 +242,7 @@ "video": { "placement": 3, "ext": { - "rp": { - } + "rp": {} }, "mimes": [ "video/mp4" @@ -283,7 +281,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -307,7 +307,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -330,7 +330,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, @@ -339,4 +342,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json index b7d8f84287..fe6c22438c 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json @@ -14,8 +14,7 @@ "val1", "val2" ], - "content": { - } + "content": {} }, "user": { "data": [ @@ -91,8 +90,7 @@ }, "ext": { "bidder": { - "video": { - }, + "video": {}, "accountId": 1001, "siteId": 113932, "zoneId": 535510 @@ -121,8 +119,7 @@ "val1", "val2" ], - "content": { - }, + "content": {}, "ext": { "rp": { "site_id": 113932 @@ -214,8 +211,7 @@ "video": { "placement": 3, "ext": { - "rp": { - } + "rp": {} }, "mimes": [ "video/mp4" @@ -244,7 +240,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -268,7 +266,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -291,7 +289,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, @@ -300,4 +301,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content.json b/adapters/rubicon/rubicontest/supplemental/no-site-content.json index bcdd9acb9a..b7acd1457b 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content.json @@ -89,8 +89,7 @@ }, "ext": { "bidder": { - "video": { - }, + "video": {}, "accountId": 1001, "siteId": 113932, "zoneId": 535510 @@ -210,8 +209,7 @@ "video": { "placement": 3, "ext": { - "rp": { - } + "rp": {} }, "mimes": [ "video/mp4" @@ -240,7 +238,9 @@ } ] }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -264,7 +264,7 @@ } } ], - "seat": "adman" + "seat": "rubicon" } ], "cur": "USD" @@ -287,7 +287,10 @@ "dealid": "test_dealid", "ext": { "prebid": { - "type": "video" + "type": "video", + "meta": { + "seat": "rubicon" + } } } }, @@ -296,4 +299,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go index 7d3dcbd70b..526c3bb3f3 100644 --- a/openrtb_ext/bid.go +++ b/openrtb_ext/bid.go @@ -70,6 +70,7 @@ type ExtBidPrebidMeta struct { RendererData json.RawMessage `json:"rendererData,omitempty"` RendererUrl string `json:"rendererUrl,omitempty"` SecondaryCategoryIDs []string `json:"secondaryCatIds,omitempty"` + Seat string `json:"seat,omitempty"` } // ExtBidPrebidVideo defines the contract for bidresponse.seatbid.bid[i].ext.prebid.video From 488c89559dafeeec175d254514f5c0ad83f5a601 Mon Sep 17 00:00:00 2001 From: support-gotham-ads Date: Wed, 25 Jun 2025 16:33:04 +0300 Subject: [PATCH 005/272] Gothamads: Add Intenze alias (#4319) --- static/bidder-info/intenze.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/intenze.yaml diff --git a/static/bidder-info/intenze.yaml b/static/bidder-info/intenze.yaml new file mode 100644 index 0000000000..14eec4d694 --- /dev/null +++ b/static/bidder-info/intenze.yaml @@ -0,0 +1,4 @@ +aliasOf: "gothamads" +endpoint: "http://lb-east.intenze.co/?pass={{.AccountID}}" +maintainer: + email: "connect@intenze.co" \ No newline at end of file From 5cb5e9c296f578e929012e5852a636a8a04113f0 Mon Sep 17 00:00:00 2001 From: ShayanK16GumGum Date: Wed, 25 Jun 2025 19:11:35 +0530 Subject: [PATCH 006/272] GumGum: Collect ad unit name for reporting (#4302) --- adapters/gumgum/gumgum.go | 15 +-- .../supplemental/ad-unit-code-test.json | 101 ++++++++++++++++++ .../sovrntest/supplemental/adunitcode.json | 2 +- openrtb_ext/imp_gumgum.go | 6 ++ 4 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 adapters/gumgum/gumgumtest/supplemental/ad-unit-code-test.json diff --git a/adapters/gumgum/gumgum.go b/adapters/gumgum/gumgum.go index 68ca84c7ce..943ccfdf14 100644 --- a/adapters/gumgum/gumgum.go +++ b/adapters/gumgum/gumgum.go @@ -48,7 +48,7 @@ func (g *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E siteCopy.Publisher = &openrtb2.Publisher{ID: strconv.FormatFloat(gumgumExt.PubID, 'f', -1, 64)} } } - + //modified Imp along with tagID is added to the request validImps = append(validImps, imp) } } @@ -136,7 +136,6 @@ func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { } return nil, err } - var gumgumExt openrtb_ext.ExtImpGumGum if err := jsonutil.Unmarshal(bidderExt.Bidder, &gumgumExt); err != nil { err = &errortypes.BadInput{ @@ -145,12 +144,18 @@ func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { return nil, err } + var ext openrtb_ext.ExtImpAdUnitCode + if err := json.Unmarshal(imp.Ext, &ext); err == nil { + if ext.Prebid.AdUnitCode != "" { + imp.TagID = ext.Prebid.AdUnitCode + } + } + if imp.Banner != nil && imp.Banner.W == nil && imp.Banner.H == nil && len(imp.Banner.Format) > 0 { bannerCopy := *imp.Banner format := bannerCopy.Format[0] bannerCopy.W = &(format.W) bannerCopy.H = &(format.H) - if gumgumExt.Slot != 0 { var err error bannerExt := getBiggerFormat(bannerCopy.Format, gumgumExt.Slot) @@ -159,10 +164,8 @@ func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { return nil, err } } - imp.Banner = &bannerCopy } - if imp.Video != nil { if gumgumExt.IrisID != "" { var err error @@ -175,7 +178,6 @@ func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { imp.Video = &videoCopy } } - if gumgumExt.Product != "" { var err error imp.Ext, err = json.Marshal(map[string]string{"product": gumgumExt.Product}) @@ -183,7 +185,6 @@ func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { return nil, err } } - return &gumgumExt, nil } diff --git a/adapters/gumgum/gumgumtest/supplemental/ad-unit-code-test.json b/adapters/gumgum/gumgumtest/supplemental/ad-unit-code-test.json new file mode 100644 index 0000000000..80421c0bbf --- /dev/null +++ b/adapters/gumgum/gumgumtest/supplemental/ad-unit-code-test.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 300, "h": 300 } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zone": "dc9d6be1" + }, + "prebid": { + "adunitcode": "test-adunit-code" + } + }, + "tagid": "test-adunit-code" + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g2.gumgum.com/providers/prbds2s/bid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-adunit-code", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 300, "h": 300 } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zone": "dc9d6be1" + }, + "prebid": { + "adunitcode": "test-adunit-code" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "seatbid": [ + { + "bid": [ + { + "crid": "2068416", + "adm": "some-test-ad", + "adid": "2068416", + "price": 5, + "id": "5736a50b-6b05-42a8-aa6d-b0a4649dcd05", + "impid": "test-imp-id", + "cid": "4747" + } + ] + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "crid": "2068416", + "adm": "some-test-ad", + "adid": "2068416", + "price": 5, + "id": "5736a50b-6b05-42a8-aa6d-b0a4649dcd05", + "impid": "test-imp-id", + "cid": "4747" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/sovrn/sovrntest/supplemental/adunitcode.json b/adapters/sovrn/sovrntest/supplemental/adunitcode.json index a4b64e4394..c913e226bc 100644 --- a/adapters/sovrn/sovrntest/supplemental/adunitcode.json +++ b/adapters/sovrn/sovrntest/supplemental/adunitcode.json @@ -123,4 +123,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/openrtb_ext/imp_gumgum.go b/openrtb_ext/imp_gumgum.go index f54234fa39..41765a6c3b 100644 --- a/openrtb_ext/imp_gumgum.go +++ b/openrtb_ext/imp_gumgum.go @@ -21,3 +21,9 @@ type ExtImpGumGumBanner struct { MaxW float64 `json:"maxw,omitempty"` MaxH float64 `json:"maxh,omitempty"` } + +type ExtImpAdUnitCode struct { + Prebid struct { + AdUnitCode string `json:"adunitcode,omitempty"` + } `json:"prebid,omitempty"` +} From fffde29583945ad1fc982c430ac6422b9752ac0f Mon Sep 17 00:00:00 2001 From: sangarbe Date: Wed, 25 Jun 2025 16:11:43 +0200 Subject: [PATCH 007/272] Seedtag: Fix required content-type header on http calls (#4299) --- adapters/seedtag/seedtag.go | 13 +++++++++---- adapters/seedtag/seedtagtest/exemplary/banner.json | 4 ++++ .../seedtagtest/exemplary/bidfloor_converted.json | 4 ++++ adapters/seedtag/seedtagtest/exemplary/video.json | 4 ++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/adapters/seedtag/seedtag.go b/adapters/seedtag/seedtag.go index 738d589fed..7836f2aaff 100644 --- a/adapters/seedtag/seedtag.go +++ b/adapters/seedtag/seedtag.go @@ -57,11 +57,16 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E return nil, []error{err} } + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + requestData := &adapters.RequestData{ - Method: http.MethodPost, - Uri: a.endpoint, - Body: requestJSON, - ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), + Method: http.MethodPost, + Uri: a.endpoint, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), } return []*adapters.RequestData{requestData}, errors diff --git a/adapters/seedtag/seedtagtest/exemplary/banner.json b/adapters/seedtag/seedtagtest/exemplary/banner.json index 94b3ef7bf4..8e390c4134 100644 --- a/adapters/seedtag/seedtagtest/exemplary/banner.json +++ b/adapters/seedtag/seedtagtest/exemplary/banner.json @@ -34,6 +34,10 @@ { "expectedRequest": { "uri": "http://url.seedtag.com", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json b/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json index 5992a58967..de0991c1e6 100644 --- a/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json +++ b/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json @@ -48,6 +48,10 @@ { "expectedRequest": { "uri": "http://url.seedtag.com", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, "body": { "id": "test-request-id", "imp": [ diff --git a/adapters/seedtag/seedtagtest/exemplary/video.json b/adapters/seedtag/seedtagtest/exemplary/video.json index c6c1f49c8d..6bfbc52ad2 100644 --- a/adapters/seedtag/seedtagtest/exemplary/video.json +++ b/adapters/seedtag/seedtagtest/exemplary/video.json @@ -36,6 +36,10 @@ { "expectedRequest": { "uri": "http://url.seedtag.com", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, "body": { "id": "test-request-id", "imp": [ From 419d60244fa643dd29ec85a36f3f44741b36047c Mon Sep 17 00:00:00 2001 From: Tommy Pettersen <42890605+TommyHPettersen@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:04:56 +0200 Subject: [PATCH 008/272] Kobler: Remove sensitive device and user data (#4295) --- adapters/kobler/kobler.go | 34 ++++++-- .../supplemental/user-data-is-removed.json | 87 +++++++++++++++++++ .../supplemental/user-ip-is-removed.json | 72 +++++++++++++++ 3 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 adapters/kobler/koblertest/supplemental/user-data-is-removed.json create mode 100644 adapters/kobler/koblertest/supplemental/user-ip-is-removed.json diff --git a/adapters/kobler/kobler.go b/adapters/kobler/kobler.go index 0a501eca46..cb1a1acaa7 100644 --- a/adapters/kobler/kobler.go +++ b/adapters/kobler/kobler.go @@ -39,20 +39,22 @@ func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.Ex testMode := false - if !slices.Contains(request.Cur, supportedCurrency) { - request.Cur = append(request.Cur, supportedCurrency) + sanitizedRequest := sanitizeRequest(*request) + + if !slices.Contains(sanitizedRequest.Cur, supportedCurrency) { + sanitizedRequest.Cur = append(sanitizedRequest.Cur, supportedCurrency) } - for i := range request.Imp { - if err := convertImpCurrency(&request.Imp[i], reqInfo); err != nil { + for i := range sanitizedRequest.Imp { + if err := convertImpCurrency(&sanitizedRequest.Imp[i], reqInfo); err != nil { errors = append(errors, err) return nil, errors } // Check the first Imp for test mode, which decides the endpoint. - if i == 0 && request.Imp[i].Ext != nil { + if i == 0 && sanitizedRequest.Imp[i].Ext != nil { var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(request.Imp[i].Ext, &bidderExt); err != nil { + if err := jsonutil.Unmarshal(sanitizedRequest.Imp[i].Ext, &bidderExt); err != nil { errors = append(errors, &errortypes.BadInput{ Message: "Error parsing bidderExt object", }) @@ -71,7 +73,7 @@ func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.Ex } } - requestJSON, err := jsonutil.Marshal(request) + requestJSON, err := jsonutil.Marshal(sanitizedRequest) if err != nil { errors = append(errors, err) return nil, errors @@ -91,7 +93,7 @@ func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.Ex Method: "POST", Uri: endpoint, Body: requestJSON, - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + ImpIDs: openrtb_ext.GetImpIDs(sanitizedRequest.Imp), Headers: headers, }) @@ -157,3 +159,19 @@ func convertImpCurrency(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) e return nil } + +func sanitizeRequest(request openrtb2.BidRequest) *openrtb2.BidRequest { + if request.Device != nil { + request.Device = sanitizeDevice(*request.Device) + } + request.User = nil + + return &request +} + +func sanitizeDevice(device openrtb2.Device) *openrtb2.Device { + device.IP = "" + device.IPv6 = "" + + return &device +} diff --git a/adapters/kobler/koblertest/supplemental/user-data-is-removed.json b/adapters/kobler/koblertest/supplemental/user-data-is-removed.json new file mode 100644 index 0000000000..104d62534b --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/user-data-is-removed.json @@ -0,0 +1,87 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "user": { + "data": [ + { + "id": "test-user-id" + } + ], + "eids": [ + { + "source": "test-source", + "uids": [ + { + "id": "test-uid" + } + ] + } + ] + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/kobler/koblertest/supplemental/user-ip-is-removed.json b/adapters/kobler/koblertest/supplemental/user-ip-is-removed.json new file mode 100644 index 0000000000..e775a40d1d --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/user-ip-is-removed.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2, + "ip": "1.1.1.1", + "ipv6": "1111::" + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} From a6a6bf5d183810322e3c838e5012189be8a774f5 Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye Date: Wed, 25 Jun 2025 18:00:52 +0200 Subject: [PATCH 009/272] New Adapter: Nexx360 (#4286) Co-authored-by: Gabriel Chicoye --- adapters/nexx360/nexx360.go | 226 +++++++++++++++++ adapters/nexx360/nexx360_test.go | 20 ++ .../nexx360test/exemplary/simple-audio.json | 158 ++++++++++++ .../exemplary/simple-banner-cookie-uid.json | 146 +++++++++++ .../exemplary/simple-banner-inapp.json | 139 ++++++++++ .../simple-banner-multiple-bids.json | 237 ++++++++++++++++++ .../simple-banner-placement-tagid.json | 112 +++++++++ .../exemplary/simple-banner-placement.json | 110 ++++++++ .../nexx360test/exemplary/simple-banner.json | 114 +++++++++ .../exemplary/simple-multi-type-banner.json | 178 +++++++++++++ .../exemplary/simple-multi-type-video.json | 178 +++++++++++++ .../nexx360test/exemplary/simple-native.json | 120 +++++++++ .../nexx360test/exemplary/simple-video.json | 162 ++++++++++++ .../supplemental/204-response.json | 121 +++++++++ .../supplemental/400-response.json | 127 ++++++++++ .../supplemental/500-response.json | 127 ++++++++++ .../supplemental/empty_seatbid.json | 125 +++++++++ .../nexx360/nexx360test/supplemental/ext.json | 33 +++ .../supplemental/invalid-bid-response.json | 77 ++++++ .../supplemental/wrong-payload.json | 82 ++++++ adapters/nexx360/params_test.go | 55 ++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_nexx360.go | 7 + static/bidder-info/1accord.yaml | 1 + static/bidder-info/easybid.yaml | 1 + static/bidder-info/nexx360.yaml | 19 ++ static/bidder-info/prismassp.yaml | 1 + static/bidder-params/nexx360.json | 32 +++ 29 files changed, 2712 insertions(+) create mode 100644 adapters/nexx360/nexx360.go create mode 100644 adapters/nexx360/nexx360_test.go create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-audio.json create mode 100755 adapters/nexx360/nexx360test/exemplary/simple-banner-cookie-uid.json create mode 100755 adapters/nexx360/nexx360test/exemplary/simple-banner-inapp.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-banner-multiple-bids.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-banner-placement-tagid.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-banner-placement.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-banner.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-multi-type-banner.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-multi-type-video.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-native.json create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-video.json create mode 100644 adapters/nexx360/nexx360test/supplemental/204-response.json create mode 100644 adapters/nexx360/nexx360test/supplemental/400-response.json create mode 100644 adapters/nexx360/nexx360test/supplemental/500-response.json create mode 100644 adapters/nexx360/nexx360test/supplemental/empty_seatbid.json create mode 100644 adapters/nexx360/nexx360test/supplemental/ext.json create mode 100644 adapters/nexx360/nexx360test/supplemental/invalid-bid-response.json create mode 100644 adapters/nexx360/nexx360test/supplemental/wrong-payload.json create mode 100644 adapters/nexx360/params_test.go create mode 100644 openrtb_ext/imp_nexx360.go create mode 100644 static/bidder-info/1accord.yaml create mode 100644 static/bidder-info/easybid.yaml create mode 100644 static/bidder-info/nexx360.yaml create mode 100644 static/bidder-info/prismassp.yaml create mode 100644 static/bidder-params/nexx360.json diff --git a/adapters/nexx360/nexx360.go b/adapters/nexx360/nexx360.go new file mode 100644 index 0000000000..f91961918c --- /dev/null +++ b/adapters/nexx360/nexx360.go @@ -0,0 +1,226 @@ +package nexx360 + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v3/version" +) + +type adapter struct { + endpoint string +} + +type Ext struct { + Nexx360 json.RawMessage `json:"nexx360"` +} + +type Nexx360Caller struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` +} + +type ReqExt struct { + Nexx360 *ReqNexx360Ext `json:"nexx360,omitempty"` +} + +type ReqNexx360Ext struct { + Caller []Nexx360Caller `json:"caller,omitempty"` +} + +type Nexx360ResBidExt struct { + BidType string `json:"bidType,omitempty"` +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{endpoint: config.Endpoint}, nil +} + +// CALLER Info used to track Prebid Server +// as one of the hops in the request to exchange + +func getVersion() string { + if version.Ver != "" { + return version.Ver + } + return "n/a" +} + +var CALLER = Nexx360Caller{"Prebid-Server", getVersion()} + +func processImps(impList []openrtb2.Imp) (imp []openrtb2.Imp, tagId string, placement string, error error) { + var imps []openrtb2.Imp + for idx, imp := range impList { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, "", "", &errortypes.BadInput{ + Message: err.Error(), + } + } + + impExt := Ext{ + Nexx360: bidderExt.Bidder, + } + + impExtJSON, err := json.Marshal(impExt) + if err != nil { + return nil, "", "", &errortypes.BadInput{ + Message: err.Error(), + } + } + + impCopy := imp + impCopy.Ext = impExtJSON + imps = append(imps, impCopy) + if idx == 0 { + var nexx360Ext openrtb_ext.ExtImpNexx360 + if err := jsonutil.Unmarshal(bidderExt.Bidder, &nexx360Ext); err != nil { + return nil, "", "", &errortypes.BadInput{ + Message: err.Error(), + } + } + tagId = nexx360Ext.TagId + placement = nexx360Ext.Placement + } + } + + return imps, tagId, placement, nil +} + +func makeReqExt() ([]byte, error) { + reqExt := ReqExt{ + Nexx360: &ReqNexx360Ext{ + Caller: []Nexx360Caller{CALLER}, + }, + } + + return json.Marshal(reqExt) +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var imp, tagId, placement, err = processImps(request.Imp) + if err != nil { + return nil, []error{err} + } + + request.Imp = imp + + urlBuilder, err := url.Parse(a.endpoint) + if err != nil { + return nil, []error{err} + } + + query := url.Values{} + + if placement != "" { + query.Add("placement", placement) + } + + if tagId != "" { + query.Add("tag_id", tagId) + } + urlBuilder.RawQuery = query.Encode() + + uri := urlBuilder.String() + + reqExt, err := makeReqExt() + if err != nil { + return nil, []error{err} + } + request.Ext = reqExt + + // Last Step + reqJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json") + + adapter := &adapters.RequestData{ + Method: http.MethodPost, + Uri: uri, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{adapter}, nil +} + +// MakeBids make the bids for the bid response. +func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected http status code: %d", responseData.StatusCode), + }} + } + + var response openrtb2.BidResponse + + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + var Bids []*adapters.TypedBid + var errors []error + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + + bidType, err := getBidType(bid) + if err != nil { + errors = append(errors, err) + continue + } + Bids = append(Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + if len(Bids) == 0 { + return nil, nil + } + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(Bids)) + bidResponse.Bids = Bids + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + + return bidResponse, errors +} + +func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + var bidExt Nexx360ResBidExt + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil { + if bidExt.BidType == "video" { + return openrtb_ext.BidTypeVideo, nil + } + if bidExt.BidType == "audio" { + return openrtb_ext.BidTypeAudio, nil + } + if bidExt.BidType == "native" { + return openrtb_ext.BidTypeNative, nil + } + if bidExt.BidType == "banner" { + return openrtb_ext.BidTypeBanner, nil + } + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unable to fetch mediaType in multi-format: %s", bid.ImpID), + } +} diff --git a/adapters/nexx360/nexx360_test.go b/adapters/nexx360/nexx360_test.go new file mode 100644 index 0000000000..f7a8741f17 --- /dev/null +++ b/adapters/nexx360/nexx360_test.go @@ -0,0 +1,20 @@ +package nexx360 + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderNexx360, config.Adapter{ + Endpoint: "http://fast.nexx360.io/prebid-server"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "nexx360test", bidder) +} diff --git a/adapters/nexx360/nexx360test/exemplary/simple-audio.json b/adapters/nexx360/nexx360test/exemplary/simple-audio.json new file mode 100644 index 0000000000..70997739ec --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-audio.json @@ -0,0 +1,158 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp3"], + "protocols": [2, 5], + "minduration": 10, + "maxduration": 30 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp3"], + "protocols": [2, 5], + "minduration": 10, + "maxduration": 30 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "ext": { + "mediaType": "audio", + "bidType": "audio", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "ext": { + "mediaType": "audio", + "bidType": "audio", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "audio" + } + ] + } + ] +} + diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-cookie-uid.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-cookie-uid.json new file mode 100755 index 0000000000..28a575d7a8 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-cookie-uid.json @@ -0,0 +1,146 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "buyeruid": "nexx360-use-id" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "buyeruid": "nexx360-use-id" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "test-ad", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "test-ad", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-inapp.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-inapp.json new file mode 100755 index 0000000000..0b65b32585 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-inapp.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "

test ad

", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "

test ad

", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-multiple-bids.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-multiple-bids.json new file mode 100644 index 0000000000..d6354acde5 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-multiple-bids.json @@ -0,0 +1,237 @@ +{ + "mockBidRequest": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnex1" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnex2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnex1", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnex1" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnex2" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "test-imp-id", + "test-imp-id2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "
Test Ad
", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnex1", + "ssp": "test" + } + } + ] + }, + { + "bid": [ + { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "
Test Ad
", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnex2", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "
Test Ad
", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnex1", + "ssp": "test" + } + }, + "type": "banner" + }, + { + "bid": { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "
Test Ad
", + "w": 300, + "h": 250, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnex2", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-placement-tagid.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-placement-tagid.json new file mode 100644 index 0000000000..1866265c49 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-placement-tagid.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "tagId": "testnexx", + "placement": "test" + + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?placement=test&tag_id=testnexx", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "placement": "test", + "tagId": "testnexx" + } + } + } + ], + "site": {} + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-placement.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-placement.json new file mode 100644 index 0000000000..01d93798c6 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-placement.json @@ -0,0 +1,110 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "placement": "test" + + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?placement=test", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "placement": "test" + } + } + } + ], + "site": {} + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner.json b/adapters/nexx360/nexx360test/exemplary/simple-banner.json new file mode 100644 index 0000000000..b8e7ba9f00 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + + } + } + } + ], + "site": {}, + "ext": { + "nexx360": "Prebid-Server", + "test": 1 + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "site": {} + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nexx360/nexx360test/exemplary/simple-multi-type-banner.json b/adapters/nexx360/nexx360test/exemplary/simple-multi-type-banner.json new file mode 100644 index 0000000000..ecc72dee18 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-multi-type-banner.json @@ -0,0 +1,178 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "

test ad

", + "h": 250, + "w": 300, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "

test ad

", + "h": 250, + "w": 300, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} + diff --git a/adapters/nexx360/nexx360test/exemplary/simple-multi-type-video.json b/adapters/nexx360/nexx360test/exemplary/simple-multi-type-video.json new file mode 100644 index 0000000000..754b3538dc --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-multi-type-video.json @@ -0,0 +1,178 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "mediaType": "video", + "bidType": "video", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "mediaType": "video", + "bidType": "video", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "video" + } + ] + } + ] +} + diff --git a/adapters/nexx360/nexx360test/exemplary/simple-native.json b/adapters/nexx360/nexx360test/exemplary/simple-native.json new file mode 100644 index 0000000000..1f0b9edcb2 --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-native.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://good.site/url" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "id": "test-request-id", + "site": { + "page": "https://good.site/url" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "grid", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.5, + "adid": "12345678", + "adm": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}", + "ext": { + "mediaType": "native", + "bidType": "native", + "tagId": "testnexx", + "ssp": "test" + }, + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.5, + "adm": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}", + "adid": "12345678", + "cid": "987", + "crid": "12345678", + "w": 300, + "h": 250, + "ext": { + "mediaType": "native", + "bidType": "native", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/exemplary/simple-video.json b/adapters/nexx360/nexx360test/exemplary/simple-video.json new file mode 100644 index 0000000000..68ce33402d --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-video.json @@ -0,0 +1,162 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "user": { + "ext": { + "eids": [ + { + "source": "criteo.com", + "uids": [ + { + "id": "criteo-eid" + } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "mediaType": "video", + "bidType": "video", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "mediaType": "video", + "bidType": "video", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "video" + } + ] + } + ] +} + diff --git a/adapters/nexx360/nexx360test/supplemental/204-response.json b/adapters/nexx360/nexx360test/supplemental/204-response.json new file mode 100644 index 0000000000..6a9cc7e5da --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/204-response.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000, + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/supplemental/400-response.json b/adapters/nexx360/nexx360test/supplemental/400-response.json new file mode 100644 index 0000000000..e430851e88 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/400-response.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000, + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected http status code: 400", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/supplemental/500-response.json b/adapters/nexx360/nexx360test/supplemental/500-response.json new file mode 100644 index 0000000000..4a06526ee1 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/500-response.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000, + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected http status code: 500", + "comparison": "literal" + } + ] +} diff --git a/adapters/nexx360/nexx360test/supplemental/empty_seatbid.json b/adapters/nexx360/nexx360test/supplemental/empty_seatbid.json new file mode 100644 index 0000000000..1abf64d3e5 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/empty_seatbid.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000, + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + } + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/supplemental/ext.json b/adapters/nexx360/nexx360test/supplemental/ext.json new file mode 100644 index 0000000000..6858423661 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/ext.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "id": "testid", + "imp": [ + { + "id": "testimpid", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + }, + { + "w": 320, + "h": 300 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "placement_id": "1265" + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ] +} diff --git a/adapters/nexx360/nexx360test/supplemental/invalid-bid-response.json b/adapters/nexx360/nexx360test/supplemental/invalid-bid-response.json new file mode 100644 index 0000000000..b3b45b2112 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/invalid-bid-response.json @@ -0,0 +1,77 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + } + } + } + ], + "site": {}, + "ext": { + "nexx360": "Prebid-Server", + "test": 1 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "site": {} + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": {}, + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "cannot unmarshal openrtb2.BidResponse.SeatBid: decode slice: expect [ or n, but found {", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/nexx360/nexx360test/supplemental/wrong-payload.json b/adapters/nexx360/nexx360test/supplemental/wrong-payload.json new file mode 100644 index 0000000000..bbcf590683 --- /dev/null +++ b/adapters/nexx360/nexx360test/supplemental/wrong-payload.json @@ -0,0 +1,82 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + } + } + } + ], + "site": {} + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/nexx360/params_test.go b/adapters/nexx360/params_test.go new file mode 100644 index 0000000000..dc21d21134 --- /dev/null +++ b/adapters/nexx360/params_test.go @@ -0,0 +1,55 @@ +package nexx360 + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/nexx360.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.nexx360 + +// TestValidParams makes sure that the Nexx360 schema accepts all imp.ext fields which we intend to support. +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.BidderNexx360, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Nexx360 params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the Nexx360 schema rejects all the imp.ext fields we don't support. +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.BidderNexx360, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"tagId": "testnexx"}`, + `{"placement": "testnexx"}`, + `{"tagId": "testnexx", "placement": "testnexx"}`, +} + +var invalidParams = []string{ + `{"productId": "inview"}`, + `{"tagId": "" }`, + `{"placement": "" }`, + `{"tagId": "testnexx", "placement": "" }`, + `{"tagId": "", "placement": "testnexx"}`, + `{}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index b7fc856d40..751934ac9b 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -161,6 +161,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/motorik" "github.com/prebid/prebid-server/v3/adapters/nativo" "github.com/prebid/prebid-server/v3/adapters/nextmillennium" + "github.com/prebid/prebid-server/v3/adapters/nexx360" "github.com/prebid/prebid-server/v3/adapters/nobid" "github.com/prebid/prebid-server/v3/adapters/ogury" "github.com/prebid/prebid-server/v3/adapters/oms" @@ -418,6 +419,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderMotorik: motorik.Builder, openrtb_ext.BidderNativo: nativo.Builder, openrtb_ext.BidderNextMillennium: nextmillennium.Builder, + openrtb_ext.BidderNexx360: nexx360.Builder, openrtb_ext.BidderNoBid: nobid.Builder, openrtb_ext.BidderOgury: ogury.Builder, openrtb_ext.BidderOms: oms.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index b0ec96f751..102c9094c3 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -179,6 +179,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderMotorik, BidderNativo, BidderNextMillennium, + BidderNexx360, BidderNoBid, BidderOgury, BidderOms, @@ -540,6 +541,7 @@ const ( BidderMotorik BidderName = "motorik" BidderNativo BidderName = "nativo" BidderNextMillennium BidderName = "nextmillennium" + BidderNexx360 BidderName = "nexx360" BidderNoBid BidderName = "nobid" BidderOgury BidderName = "ogury" BidderOms BidderName = "oms" diff --git a/openrtb_ext/imp_nexx360.go b/openrtb_ext/imp_nexx360.go new file mode 100644 index 0000000000..29297aece2 --- /dev/null +++ b/openrtb_ext/imp_nexx360.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtNexx360 defines the contract for bidrequest.imp[i].ext.prebid.bidder.nexx360 +type ExtImpNexx360 struct { + TagId string `json:"tagId,omitempty"` + Placement string `json:"placement,omitempty"` // Placement ID +} diff --git a/static/bidder-info/1accord.yaml b/static/bidder-info/1accord.yaml new file mode 100644 index 0000000000..4a6b8199be --- /dev/null +++ b/static/bidder-info/1accord.yaml @@ -0,0 +1 @@ +aliasOf: "nexx360" diff --git a/static/bidder-info/easybid.yaml b/static/bidder-info/easybid.yaml new file mode 100644 index 0000000000..4a6b8199be --- /dev/null +++ b/static/bidder-info/easybid.yaml @@ -0,0 +1 @@ +aliasOf: "nexx360" diff --git a/static/bidder-info/nexx360.yaml b/static/bidder-info/nexx360.yaml new file mode 100644 index 0000000000..0a0b186ec9 --- /dev/null +++ b/static/bidder-info/nexx360.yaml @@ -0,0 +1,19 @@ +endpoint: "http://fast.nexx360.io/prebid-server" +maintainer: + email: "tech@nexx360.io" +endpointCompression: gzip +geoscope: + - global +capabilities: + app: + mediaTypes: + - banner + - video + - native + - audio + site: + mediaTypes: + - banner + - video + - native + - audio diff --git a/static/bidder-info/prismassp.yaml b/static/bidder-info/prismassp.yaml new file mode 100644 index 0000000000..4a6b8199be --- /dev/null +++ b/static/bidder-info/prismassp.yaml @@ -0,0 +1 @@ +aliasOf: "nexx360" diff --git a/static/bidder-params/nexx360.json b/static/bidder-params/nexx360.json new file mode 100644 index 0000000000..a2f35276ac --- /dev/null +++ b/static/bidder-params/nexx360.json @@ -0,0 +1,32 @@ + +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Nexx360 Adapter Params", + "description": "A schema which validates params accepted by the Nexx360 adapter", + + "type": "object", + "properties": { + "tagId": { + "type": "string", + "minLength": 1, + "description": "TagId" + }, + "placement": { + "type": "string", + "minLength": 1, + "description": "Placement" + } + }, + "anyOf": [ + { + "required": [ + "tagId" + ] + }, + { + "required": [ + "placement" + ] + } + ] + } \ No newline at end of file From afab3e56a1ddad8acb42acc507b1ca44dbe6f288 Mon Sep 17 00:00:00 2001 From: Sigma Software Date: Wed, 25 Jun 2025 20:37:19 +0000 Subject: [PATCH 010/272] HTTP Fetcher: Implement RFC 3986 compatibility as optional (#4272) --- config/config.go | 1 + config/config_test.go | 6 + config/stored_requests.go | 5 +- .../backends/http_fetcher/fetcher.go | 83 +++++--- .../backends/http_fetcher/fetcher_test.go | 196 +++++++++++++++--- stored_requests/config/config.go | 2 +- stored_requests/config/config_test.go | 4 +- 7 files changed, 235 insertions(+), 62 deletions(-) diff --git a/config/config.go b/config/config.go index 30f8d69adc..9434eab5ef 100644 --- a/config/config.go +++ b/config/config.go @@ -994,6 +994,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("stored_requests.directorypath", "./stored_requests/data/by_id") v.SetDefault("stored_requests.http.endpoint", "") v.SetDefault("stored_requests.http.amp_endpoint", "") + v.SetDefault("stored_requests.http.use_rfc3986_compliant_request_builder", false) v.SetDefault("stored_requests.in_memory_cache.type", "none") v.SetDefault("stored_requests.in_memory_cache.ttl_seconds", 0) v.SetDefault("stored_requests.in_memory_cache.request_cache_size_bytes", 0) diff --git a/config/config_test.go b/config/config_test.go index a68f478a64..a2453d718b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -164,6 +164,9 @@ func TestDefaults(t *testing.T) { cmpInts(t, "stored_requests_timeout_ms", 50, cfg.StoredRequestsTimeout) cmpBools(t, "stored_requests.filesystem.enabled", false, cfg.StoredRequests.Files.Enabled) cmpStrings(t, "stored_requests.filesystem.directorypath", "./stored_requests/data/by_id", cfg.StoredRequests.Files.Path) + cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) + cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) + cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) cmpBools(t, "auto_gen_source_tid", true, cfg.AutoGenSourceTID) cmpBools(t, "generate_bid_id", false, cfg.GenerateBidID) cmpStrings(t, "experiment.adscert.mode", "off", cfg.Experiment.AdCerts.Mode) @@ -615,6 +618,9 @@ func TestFullConfig(t *testing.T) { cmpInts(t, "auction_timeouts_ms.default", 50, int(cfg.AuctionTimeouts.Default)) cmpInts(t, "auction_timeouts_ms.max", 123, int(cfg.AuctionTimeouts.Max)) cmpInts(t, "stored_request_timeout_ms", 75, cfg.StoredRequestsTimeout) + cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) + cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) + cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) cmpStrings(t, "cache.scheme", "http", cfg.CacheURL.Scheme) cmpStrings(t, "cache.host", "prebidcache.net", cfg.CacheURL.Host) cmpStrings(t, "cache.query", "uuid=%PBS_CACHE_UUID%", cfg.CacheURL.Query) diff --git a/config/stored_requests.go b/config/stored_requests.go index 9a3ab260ec..2e8d1e7f88 100644 --- a/config/stored_requests.go +++ b/config/stored_requests.go @@ -107,8 +107,9 @@ type FileFetcherConfig struct { // HTTPFetcherConfig configures a stored_requests/backends/http_fetcher/fetcher.go type HTTPFetcherConfig struct { - Endpoint string `mapstructure:"endpoint"` - AmpEndpoint string `mapstructure:"amp_endpoint"` + Endpoint string `mapstructure:"endpoint"` + AmpEndpoint string `mapstructure:"amp_endpoint"` + UseRfcCompliantBuilder bool `mapstructure:"use_rfc3986_compliant_request_builder"` } // Migrate combined stored_requests+amp configuration to separate simple config sections diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go index 7f765b9932..a261fb6bdf 100644 --- a/stored_requests/backends/http_fetcher/fetcher.go +++ b/stored_requests/backends/http_fetcher/fetcher.go @@ -24,9 +24,15 @@ import ( // Stored requests // GET {endpoint}?request-ids=["req1","req2"]&imp-ids=["imp1","imp2","imp3"] // +// If useRfcCompliantBuilder is true (symbols will be URLEncoded) +// GET {endpoint}?request-id=req1&request-id=req2&imp-id=imp1&imp-id=imp2&imp-id=imp3 +// // Accounts // GET {endpoint}?account-ids=["acc1","acc2"] // +// If UseRfcCompliantBuilder is true (symbols will be URLEncoded) +// GET {endpoint}?account-id=acc1&account-id=acc2 +// // The above endpoints should return a payload like: // // { @@ -49,33 +55,26 @@ import ( // "acc2": { ... config data for acc2 ... }, // }, // } -func NewFetcher(client *http.Client, endpoint string) *HttpFetcher { - // Do some work up-front to figure out if the (configurable) endpoint has a query string or not. - // When we build requests, we'll either want to add `?request-ids=...&imp-ids=...` _or_ - // `&request-ids=...&imp-ids=...`. +func NewFetcher(client *http.Client, endpoint string, useRfcCompliantBuilder bool) *HttpFetcher { + endpointURL, err := url.Parse(endpoint) - if _, err := url.Parse(endpoint); err != nil { + if err != nil { glog.Fatalf(`Invalid endpoint "%s": %v`, endpoint, err) } glog.Infof("Making http_fetcher for endpoint %v", endpoint) - urlPrefix := endpoint - if strings.Contains(endpoint, "?") { - urlPrefix = urlPrefix + "&" - } else { - urlPrefix = urlPrefix + "?" - } - return &HttpFetcher{ - client: client, - Endpoint: urlPrefix, + client: client, + EndpointURL: endpointURL, + UseRfcCompliantBuilder: useRfcCompliantBuilder, } } type HttpFetcher struct { - client *http.Client - Endpoint string - Categories map[string]map[string]stored_requests.Category + client *http.Client + EndpointURL *url.URL + UseRfcCompliantBuilder bool + Categories map[string]map[string]stored_requests.Category } func (fetcher *HttpFetcher) FetchRequests(ctx context.Context, requestIDs []string, impIDs []string) (requestData map[string]json.RawMessage, impData map[string]json.RawMessage, errs []error) { @@ -83,7 +82,7 @@ func (fetcher *HttpFetcher) FetchRequests(ctx context.Context, requestIDs []stri return nil, nil, nil } - httpReq, err := buildRequest(fetcher.Endpoint, requestIDs, impIDs) + httpReq, err := fetcher.buildRequest(requestIDs, impIDs) if err != nil { return nil, nil, []error{err} } @@ -106,6 +105,9 @@ func (fetcher *HttpFetcher) FetchResponses(ctx context.Context, ids []string) (d // Request format is similar to the one for requests: // GET {endpoint}?account-ids=["account1","account2",...] // +// If UseRfcCompliantBuilder is true (symbols will be URLEncoded): +// GET {endpoint}?account-id=account1&account-id=account2&... +// // The endpoint is expected to respond with a JSON map with accountID -> json.RawMessage // // { @@ -117,7 +119,17 @@ func (fetcher *HttpFetcher) FetchAccounts(ctx context.Context, accountIDs []stri if len(accountIDs) == 0 { return nil, nil } - httpReq, err := http.NewRequestWithContext(ctx, "GET", fetcher.Endpoint+"account-ids=[\""+strings.Join(accountIDs, "\",\"")+"\"]", nil) + u := fetcher.EndpointURL + q := u.Query() + if !fetcher.UseRfcCompliantBuilder { + q.Set("account-ids", `["`+strings.Join(accountIDs, `","`)+`"]`) + } else { + for _, id := range accountIDs { + q.Add("account-id", id) + } + } + u.RawQuery = q.Encode() + httpReq, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) if err != nil { return nil, []error{ fmt.Errorf(`Error fetching accounts %v via http: build request failed with %v`, accountIDs, err), @@ -184,10 +196,10 @@ func (fetcher *HttpFetcher) FetchCategories(ctx context.Context, primaryAdServer var dataName, url string if publisherId != "" { dataName = fmt.Sprintf("%s_%s", primaryAdServer, publisherId) - url = fmt.Sprintf("%s/%s/%s.json", strings.TrimSuffix(fetcher.Endpoint, "?"), primaryAdServer, publisherId) + url = fmt.Sprintf("%s/%s/%s.json", fetcher.EndpointURL.String(), primaryAdServer, publisherId) } else { dataName = primaryAdServer - url = fmt.Sprintf("%s/%s.json", strings.TrimSuffix(fetcher.Endpoint, "?"), primaryAdServer) + url = fmt.Sprintf("%s/%s.json", fetcher.EndpointURL.String(), primaryAdServer) } if data, ok := fetcher.Categories[dataName]; ok { @@ -227,16 +239,31 @@ func (fetcher *HttpFetcher) FetchCategories(ctx context.Context, primaryAdServer } } -func buildRequest(endpoint string, requestIDs []string, impIDs []string) (*http.Request, error) { - if len(requestIDs) > 0 && len(impIDs) > 0 { - return http.NewRequest("GET", endpoint+"request-ids=[\""+strings.Join(requestIDs, "\",\"")+"\"]&imp-ids=[\""+strings.Join(impIDs, "\",\"")+"\"]", nil) - } else if len(requestIDs) > 0 { - return http.NewRequest("GET", endpoint+"request-ids=[\""+strings.Join(requestIDs, "\",\"")+"\"]", nil) - } else { - return http.NewRequest("GET", endpoint+"imp-ids=[\""+strings.Join(impIDs, "\",\"")+"\"]", nil) +func AddQueryParam(q *url.Values, paramName string, ids []string, useRfcCompliantBuilder bool) { + if len(ids) > 0 { + if !useRfcCompliantBuilder { + q.Set(paramName+"s", `["`+strings.Join(ids, `","`)+`"]`) + } else { + for _, requestID := range ids { + q.Add(paramName, requestID) + } + } } } +func (fetcher *HttpFetcher) buildRequest(requestIDs []string, impIDs []string) (*http.Request, error) { + u := *fetcher.EndpointURL + + q := u.Query() + + AddQueryParam(&q, "request-id", requestIDs, fetcher.UseRfcCompliantBuilder) + AddQueryParam(&q, "imp-id", impIDs, fetcher.UseRfcCompliantBuilder) + + u.RawQuery = q.Encode() + + return http.NewRequest("GET", u.String(), nil) +} + func unpackResponse(resp *http.Response) (requestData map[string]json.RawMessage, impData map[string]json.RawMessage, errs []error) { respBytes, err := io.ReadAll(resp.Body) if err != nil { diff --git a/stored_requests/backends/http_fetcher/fetcher_test.go b/stored_requests/backends/http_fetcher/fetcher_test.go index 9ba85eac94..9d014eaf5a 100644 --- a/stored_requests/backends/http_fetcher/fetcher_test.go +++ b/stored_requests/backends/http_fetcher/fetcher_test.go @@ -14,8 +14,18 @@ import ( "github.com/stretchr/testify/assert" ) +func TestSingleReqRfcCompliant(t *testing.T) { + fetcher, close := newTestFetcher(t, []string{"req-1"}, nil, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1"}, nil) + assert.Empty(t, errs, "Unexpected errors fetching known requests") + assertMapKeys(t, reqData, "req-1") + assert.Empty(t, impData, "Unexpected imps returned fetching just requests") +} + func TestSingleReq(t *testing.T) { - fetcher, close := newTestFetcher(t, []string{"req-1"}, nil) + fetcher, close := newTestFetcher(t, []string{"req-1"}, nil, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1"}, nil) @@ -24,8 +34,18 @@ func TestSingleReq(t *testing.T) { assert.Empty(t, impData, "Unexpected imps returned fetching just requests") } +func TestSeveralReqsRfcCompliant(t *testing.T) { + fetcher, close := newTestFetcher(t, []string{"req-1", "req-2"}, nil, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1", "req-2"}, nil) + assert.Empty(t, errs, "Unexpected errors fetching known requests") + assertMapKeys(t, reqData, "req-1", "req-2") + assert.Empty(t, impData, "Unexpected imps returned fetching just requests") +} + func TestSeveralReqs(t *testing.T) { - fetcher, close := newTestFetcher(t, []string{"req-1", "req-2"}, nil) + fetcher, close := newTestFetcher(t, []string{"req-1", "req-2"}, nil, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1", "req-2"}, nil) @@ -34,8 +54,18 @@ func TestSeveralReqs(t *testing.T) { assert.Empty(t, impData, "Unexpected imps returned fetching just requests") } +func TestSingleImpRfcCompliant(t *testing.T) { + fetcher, close := newTestFetcher(t, nil, []string{"imp-1"}, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), nil, []string{"imp-1"}) + assert.Empty(t, errs, "Unexpected errors fetching known imps") + assert.Empty(t, reqData, "Unexpected requests returned fetching just imps") + assertMapKeys(t, impData, "imp-1") +} + func TestSingleImp(t *testing.T) { - fetcher, close := newTestFetcher(t, nil, []string{"imp-1"}) + fetcher, close := newTestFetcher(t, nil, []string{"imp-1"}, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), nil, []string{"imp-1"}) @@ -44,8 +74,18 @@ func TestSingleImp(t *testing.T) { assertMapKeys(t, impData, "imp-1") } +func TestSeveralImpsRfcCompliant(t *testing.T) { + fetcher, close := newTestFetcher(t, nil, []string{"imp-1", "imp-2"}, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), nil, []string{"imp-1", "imp-2"}) + assert.Empty(t, errs, "Unexpected errors fetching known imps") + assert.Empty(t, reqData, "Unexpected requests returned fetching just imps") + assertMapKeys(t, impData, "imp-1", "imp-2") +} + func TestSeveralImps(t *testing.T) { - fetcher, close := newTestFetcher(t, nil, []string{"imp-1", "imp-2"}) + fetcher, close := newTestFetcher(t, nil, []string{"imp-1", "imp-2"}, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), nil, []string{"imp-1", "imp-2"}) @@ -54,8 +94,18 @@ func TestSeveralImps(t *testing.T) { assertMapKeys(t, impData, "imp-1", "imp-2") } +func TestReqsAndImpsRfcCompliant(t *testing.T) { + fetcher, close := newTestFetcher(t, []string{"req-1"}, []string{"imp-1"}, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1"}, []string{"imp-1"}) + assert.Empty(t, errs, "Unexpected errors fetching known reqs and imps") + assertMapKeys(t, reqData, "req-1") + assertMapKeys(t, impData, "imp-1") +} + func TestReqsAndImps(t *testing.T) { - fetcher, close := newTestFetcher(t, []string{"req-1"}, []string{"imp-1"}) + fetcher, close := newTestFetcher(t, []string{"req-1"}, []string{"imp-1"}, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1"}, []string{"imp-1"}) @@ -64,8 +114,18 @@ func TestReqsAndImps(t *testing.T) { assertMapKeys(t, impData, "imp-1") } +func TestMissingValuesRfcCompliant(t *testing.T) { + fetcher, close := newEmptyFetcher(t, []string{"req-1", "req-2"}, []string{"imp-1"}, true) + defer close() + + reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1", "req-2"}, []string{"imp-1"}) + assert.Empty(t, reqData, "Fetching unknown reqs should return no reqs") + assert.Empty(t, impData, "Fetching unknown imps should return no imps") + assert.Len(t, errs, 3, "Fetching 3 unknown reqs+imps should return 3 errors") +} + func TestMissingValues(t *testing.T) { - fetcher, close := newEmptyFetcher(t, []string{"req-1", "req-2"}, []string{"imp-1"}) + fetcher, close := newEmptyFetcher(t, []string{"req-1", "req-2"}, []string{"imp-1"}, false) defer close() reqData, impData, errs := fetcher.FetchRequests(context.Background(), []string{"req-1", "req-2"}, []string{"imp-1"}) @@ -74,8 +134,17 @@ func TestMissingValues(t *testing.T) { assert.Len(t, errs, 3, "Fetching 3 unknown reqs+imps should return 3 errors") } +func TestFetchAccountsRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, true) + defer close() + + accData, errs := fetcher.FetchAccounts(context.Background(), []string{"acc-1", "acc-2"}) + assert.Empty(t, errs, "Unexpected error fetching known accounts") + assertMapKeys(t, accData, "acc-1", "acc-2") +} + func TestFetchAccounts(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, false) defer close() accData, errs := fetcher.FetchAccounts(context.Background(), []string{"acc-1", "acc-2"}) @@ -101,8 +170,17 @@ func TestFetchAccountsBadJSON(t *testing.T) { assert.Nil(t, accData, "Fetching account with broken json should return nil account map") } +func TestFetchAccountsNoIDsProvidedRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, true) + defer close() + + accData, errs := fetcher.FetchAccounts(context.TODO(), []string{}) + assert.Empty(t, errs, "Unexpected error fetching empty account list") + assert.Nil(t, accData, "Fetching empty account list should return nil") +} + func TestFetchAccountsNoIDsProvided(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, false) defer close() accData, errs := fetcher.FetchAccounts(context.TODO(), []string{}) @@ -110,9 +188,19 @@ func TestFetchAccountsNoIDsProvided(t *testing.T) { assert.Nil(t, accData, "Fetching empty account list should return nil") } +// Force build request failure by not providing a context +func TestFetchAccountsFailedBuildRequestRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, true) + defer close() + + accData, errs := fetcher.FetchAccounts(nil, []string{"acc-1"}) //nolint: staticcheck // test handling of a nil context + assert.Len(t, errs, 1, "Fetching accounts without context should result in error ") + assert.Nil(t, accData, "Fetching accounts without context should return nil") +} + // Force build request failure by not providing a context func TestFetchAccountsFailedBuildRequest(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, false) defer close() accData, errs := fetcher.FetchAccounts(nil, []string{"acc-1"}) //nolint: staticcheck // test handling of a nil context @@ -120,9 +208,21 @@ func TestFetchAccountsFailedBuildRequest(t *testing.T) { assert.Nil(t, accData, "Fetching accounts without context should return nil") } +// Force http error via request timeout +func TestFetchAccountsContextTimeoutRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, true) + defer close() + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(0)) + defer cancel() + accData, errs := fetcher.FetchAccounts(ctx, []string{"acc-1"}) + assert.Len(t, errs, 1, "Expected context timeout error") + assert.Nil(t, accData, "Unexpected account data returned instead of timeout") +} + // Force http error via request timeout func TestFetchAccountsContextTimeout(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1", "acc-2"}, false) defer close() ctx, cancel := context.WithTimeout(context.Background(), time.Duration(0)) @@ -132,8 +232,17 @@ func TestFetchAccountsContextTimeout(t *testing.T) { assert.Nil(t, accData, "Unexpected account data returned instead of timeout") } +func TestFetchAccountRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}, true) + defer close() + + account, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{"disabled":true}`), "acc-1") + assert.Empty(t, errs, "Unexpected error fetching existing account") + assert.JSONEq(t, `{"disabled": true, "id":"acc-1"}`, string(account), "Unexpected account data fetching existing account") +} + func TestFetchAccount(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}, false) defer close() account, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{"disabled":true}`), "acc-1") @@ -141,8 +250,17 @@ func TestFetchAccount(t *testing.T) { assert.JSONEq(t, `{"disabled": true, "id":"acc-1"}`, string(account), "Unexpected account data fetching existing account") } +func TestAccountMergeErrorRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}, true) + defer close() + + _, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{"disabled"}`), "acc-1") + assert.Error(t, errs[0]) + assert.Equal(t, fmt.Errorf("Invalid JSON Document"), errs[0]) +} + func TestAccountMergeError(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}) + fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}, false) defer close() _, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{"disabled"}`), "acc-1") @@ -159,8 +277,17 @@ func TestFetchAccountNoData(t *testing.T) { assert.Nil(t, unknownAccount, "Retrieving unknown account should return nil json.RawMessage") } +func TestFetchAccountNoIDProvidedRfcCompliant(t *testing.T) { + fetcher, close := newTestAccountFetcher(t, nil, true) + defer close() + + account, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{disabled":true}`), "") + assert.Len(t, errs, 1, "Fetching account with empty id should error") + assert.Nil(t, account, "Fetching account with empty id should return nil") +} + func TestFetchAccountNoIDProvided(t *testing.T) { - fetcher, close := newTestAccountFetcher(t, nil) + fetcher, close := newTestAccountFetcher(t, nil, false) defer close() account, errs := fetcher.FetchAccount(context.Background(), json.RawMessage(`{disabled":true}`), "") @@ -182,7 +309,7 @@ func newFetcherBrokenBackend() (fetcher *HttpFetcher, closer func()) { w.WriteHeader(http.StatusInternalServerError) } server := httptest.NewServer(http.HandlerFunc(handler)) - return NewFetcher(server.Client(), server.URL), server.Close + return NewFetcher(server.Client(), server.URL, false), server.Close } func newFetcherBadJSON() (fetcher *HttpFetcher, closer func()) { @@ -190,26 +317,32 @@ func newFetcherBadJSON() (fetcher *HttpFetcher, closer func()) { w.Write([]byte(`broken JSON`)) } server := httptest.NewServer(http.HandlerFunc(handler)) - return NewFetcher(server.Client(), server.URL), server.Close + return NewFetcher(server.Client(), server.URL, false), server.Close } -func newEmptyFetcher(t *testing.T, expectReqIDs []string, expectImpIDs []string) (fetcher *HttpFetcher, closer func()) { - handler := newHandler(t, expectReqIDs, expectImpIDs, jsonifyToNull) +func newEmptyFetcher(t *testing.T, expectReqIDs []string, expectImpIDs []string, useRfcCompliantBuilder bool) (fetcher *HttpFetcher, closer func()) { + handler := newHandler(t, expectReqIDs, expectImpIDs, jsonifyToNull, useRfcCompliantBuilder) server := httptest.NewServer(http.HandlerFunc(handler)) - return NewFetcher(server.Client(), server.URL), server.Close + return NewFetcher(server.Client(), server.URL, useRfcCompliantBuilder), server.Close } -func newTestFetcher(t *testing.T, expectReqIDs []string, expectImpIDs []string) (fetcher *HttpFetcher, closer func()) { - handler := newHandler(t, expectReqIDs, expectImpIDs, jsonifyID) +func newTestFetcher(t *testing.T, expectReqIDs []string, expectImpIDs []string, useRfcCompliantBuilder bool) (fetcher *HttpFetcher, closer func()) { + handler := newHandler(t, expectReqIDs, expectImpIDs, jsonifyID, useRfcCompliantBuilder) server := httptest.NewServer(http.HandlerFunc(handler)) - return NewFetcher(server.Client(), server.URL), server.Close + return NewFetcher(server.Client(), server.URL, useRfcCompliantBuilder), server.Close } -func newHandler(t *testing.T, expectReqIDs []string, expectImpIDs []string, jsonifier func(string) json.RawMessage) func(w http.ResponseWriter, r *http.Request) { +func newHandler(t *testing.T, expectReqIDs []string, expectImpIDs []string, jsonifier func(string) json.RawMessage, useRfcCompliantBuilder bool) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - gotReqIDs := richSplit(query.Get("request-ids")) - gotImpIDs := richSplit(query.Get("imp-ids")) + var gotReqIDs, gotImpIDs []string + if !useRfcCompliantBuilder { + gotReqIDs = richSplit(query.Get("request-ids")) + gotImpIDs = richSplit(query.Get("imp-ids")) + } else { + gotReqIDs = query["request-id"] + gotImpIDs = query["imp-id"] + } assertMatches(t, gotReqIDs, expectReqIDs) assertMatches(t, gotImpIDs, expectImpIDs) @@ -243,16 +376,21 @@ func newHandler(t *testing.T, expectReqIDs []string, expectImpIDs []string, json } } -func newTestAccountFetcher(t *testing.T, expectAccIDs []string) (fetcher *HttpFetcher, closer func()) { - handler := newAccountHandler(t, expectAccIDs) +func newTestAccountFetcher(t *testing.T, expectAccIDs []string, useRfcCompliantBuilder bool) (fetcher *HttpFetcher, closer func()) { + handler := newAccountHandler(t, expectAccIDs, useRfcCompliantBuilder) server := httptest.NewServer(http.HandlerFunc(handler)) - return NewFetcher(server.Client(), server.URL), server.Close + return NewFetcher(server.Client(), server.URL, useRfcCompliantBuilder), server.Close } -func newAccountHandler(t *testing.T, expectAccIDs []string) func(w http.ResponseWriter, r *http.Request) { +func newAccountHandler(t *testing.T, expectAccIDs []string, useRfcCompliantBuilder bool) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - gotAccIDs := richSplit(query.Get("account-ids")) + var gotAccIDs []string + if !useRfcCompliantBuilder { + gotAccIDs = richSplit(query.Get("account-ids")) + } else { + gotAccIDs = query["account-id"] + } assertMatches(t, gotAccIDs, expectAccIDs) diff --git a/stored_requests/config/config.go b/stored_requests/config/config.go index 6950c5ebc0..fd82e87842 100644 --- a/stored_requests/config/config.go +++ b/stored_requests/config/config.go @@ -166,7 +166,7 @@ func newFetcher(cfg *config.StoredRequests, client *http.Client, provider db_pro } if cfg.HTTP.Endpoint != "" { glog.Infof("Loading Stored %s data via HTTP. endpoint=%s", cfg.DataType(), cfg.HTTP.Endpoint) - idList = append(idList, http_fetcher.NewFetcher(client, cfg.HTTP.Endpoint)) + idList = append(idList, http_fetcher.NewFetcher(client, cfg.HTTP.Endpoint, cfg.HTTP.UseRfcCompliantBuilder)) } fetcher = consolidate(cfg.DataType(), idList) diff --git a/stored_requests/config/config_test.go b/stored_requests/config/config_test.go index 917e3e975c..87b396c926 100644 --- a/stored_requests/config/config_test.go +++ b/stored_requests/config/config_test.go @@ -134,8 +134,8 @@ func TestNewHTTPFetcher(t *testing.T) { }, }, nil, nil) if httpFetcher, ok := fetcher.(*http_fetcher.HttpFetcher); ok { - if httpFetcher.Endpoint != "stored-requests.prebid.com?" { - t.Errorf("The HTTP fetcher is using the wrong endpoint. Expected %s, got %s", "stored-requests.prebid.com?", httpFetcher.Endpoint) + if httpFetcher.EndpointURL.String() != "stored-requests.prebid.com" { + t.Errorf("The HTTP fetcher is using the wrong endpoint. Expected %s, got %s", "stored-requests.prebid.com", httpFetcher.EndpointURL) } } else { t.Errorf("An HTTP Fetching config should return an HTTPFetcher. Got %v", fetcher) From c75974dfe3b0a48e538fd3ec839edca7314b2f33 Mon Sep 17 00:00:00 2001 From: Sigma Software Date: Thu, 26 Jun 2025 13:03:19 +0000 Subject: [PATCH 011/272] Targeting: Add configurable targeting prefix (#4355) --- adservertargeting/respdataprocessor.go | 7 +- config/account.go | 1 + endpoints/openrtb2/video_auction.go | 21 ++- endpoints/openrtb2/video_auction_test.go | 43 ++++++- errortypes/code.go | 2 + exchange/exchange.go | 11 +- exchange/targeting.go | 38 +++--- exchange/targeting_test.go | 156 ++++++++++++++++++++--- exchange/utils.go | 44 ++++++- exchange/utils_test.go | 78 +++++++++++- openrtb_ext/bid.go | 51 ++++---- openrtb_ext/bid_test.go | 12 +- openrtb_ext/request.go | 2 + 13 files changed, 374 insertions(+), 92 deletions(-) diff --git a/adservertargeting/respdataprocessor.go b/adservertargeting/respdataprocessor.go index 529abcfd15..beeaae68de 100644 --- a/adservertargeting/respdataprocessor.go +++ b/adservertargeting/respdataprocessor.go @@ -103,16 +103,13 @@ func resolveKey(respTargetingData ResponseTargetingData, bidderName string) stri func truncateTargetingKeys(targetingData map[string]string, truncateTargetAttribute *int) map[string]string { maxLength := MaxKeyLength - if truncateTargetAttribute != nil { + if truncateTargetAttribute != nil && *truncateTargetAttribute > 0 { maxLength = *truncateTargetAttribute - if maxLength <= 0 { - maxLength = MaxKeyLength - } } targetingDataTruncated := make(map[string]string) for key, value := range targetingData { - newKey := openrtb_ext.TargetingKey(key).TruncateKey(maxLength) + newKey := openrtb_ext.TargetingKey(key).TruncateKey("", maxLength) targetingDataTruncated[newKey] = value } return targetingDataTruncated diff --git a/config/account.go b/config/account.go index 3d7e0f8c80..c87ce5d1b1 100644 --- a/config/account.go +++ b/config/account.go @@ -43,6 +43,7 @@ type Account struct { BidAdjustments *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"` Privacy AccountPrivacy `mapstructure:"privacy" json:"privacy"` PreferredMediaType openrtb_ext.PreferredMediaType `mapstructure:"preferredmediatype" json:"preferredmediatype"` + TargetingPrefix string `mapstructure:"targeting_prefix" json:"targeting_prefix"` } // CookieSync represents the account-level defaults for the cookie sync endpoint. diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index f3dbd2246c..50b54c5b33 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -549,7 +549,7 @@ func buildVideoResponse(bidresponse *openrtb2.BidResponse, podErrors []PodError) if err := jsonutil.UnmarshalValid(bid.Ext, &tempRespBidExt); err != nil { return nil, err } - if tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbVastCacheKey, seatBid.Seat)] == "" { + if findTargetingByKey(tempRespBidExt.Prebid.Targeting, formatTargetingKey(openrtb_ext.VastCacheKey, seatBid.Seat)) == "" { continue } @@ -558,10 +558,10 @@ func buildVideoResponse(bidresponse *openrtb2.BidResponse, podErrors []PodError) podId, _ := strconv.ParseInt(podNum, 0, 64) videoTargeting := openrtb_ext.VideoTargeting{ - HbPb: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbpbConstantKey, seatBid.Seat)], - HbPbCatDur: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbCategoryDurationKey, seatBid.Seat)], - HbCacheID: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbVastCacheKey, seatBid.Seat)], - HbDeal: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbDealIDConstantKey, seatBid.Seat)], + HbPb: findTargetingByKey(tempRespBidExt.Prebid.Targeting, formatTargetingKey(openrtb_ext.PbKey, seatBid.Seat)), + HbPbCatDur: findTargetingByKey(tempRespBidExt.Prebid.Targeting, formatTargetingKey(openrtb_ext.CategoryDurationKey, seatBid.Seat)), + HbCacheID: findTargetingByKey(tempRespBidExt.Prebid.Targeting, formatTargetingKey(openrtb_ext.VastCacheKey, seatBid.Seat)), + HbDeal: findTargetingByKey(tempRespBidExt.Prebid.Targeting, formatTargetingKey(openrtb_ext.DealKey, seatBid.Seat)), } adPod := findAdPod(podId, adPods) @@ -607,6 +607,17 @@ func formatTargetingKey(key openrtb_ext.TargetingKey, bidderName string) string return fullKey } +func findTargetingByKey(targetingMap map[string]string, keyWithoutPrefix string) string { + for k, v := range targetingMap { + prefixIndex := strings.Index(k, "_") + // find potentially truncated key in original key name without prefixes + if prefixIndex > 0 && strings.HasPrefix(keyWithoutPrefix, k[prefixIndex:]) { + return v + } + } + return "" +} + func findAdPod(podInd int64, pods []*openrtb_ext.AdPod) *openrtb_ext.AdPod { for _, pod := range pods { if pod.PodId == podInd { diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go index 93f7f6fcf3..cd3e0d9c37 100644 --- a/endpoints/openrtb2/video_auction_test.go +++ b/endpoints/openrtb2/video_auction_test.go @@ -1147,13 +1147,48 @@ func TestVideoEndpointAppendBidderNames(t *testing.T) { } func TestFormatTargetingKey(t *testing.T) { - res := formatTargetingKey(openrtb_ext.HbCategoryDurationKey, "appnexus") - assert.Equal(t, "hb_pb_cat_dur_appnex", res, "Tergeting key constructed incorrectly") + res := formatTargetingKey(openrtb_ext.CategoryDurationKey, "appnexus") + assert.Equal(t, "_pb_cat_dur_appnexus", res, "Tergeting key constructed incorrectly") } func TestFormatTargetingKeyLongKey(t *testing.T) { - res := formatTargetingKey(openrtb_ext.HbpbConstantKey, "20.00") - assert.Equal(t, "hb_pb_20.00", res, "Tergeting key constructed incorrectly") + res := formatTargetingKey(openrtb_ext.PbKey, "20.00") + assert.Equal(t, "_pb_20.00", res, "Tergeting key constructed incorrectly") +} + +func TestFindTargetingByKey(t *testing.T) { + tests := []struct { + name string + targetingMap map[string]string + keyWithoutPrefix string + expectedResult string + }{ + { + name: "Correct match", + targetingMap: map[string]string{ + "hb_key": "hb_key12345454", + }, + keyWithoutPrefix: "_key12345454", + expectedResult: "hb_key12345454", + }, + { + name: "Dismatching", + targetingMap: map[string]string{ + "hb_key": "hb_key12345454", + }, + keyWithoutPrefix: "12345454", + expectedResult: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := findTargetingByKey(tt.targetingMap, tt.keyWithoutPrefix) + if result != tt.expectedResult { + t.Errorf("expected %v, got %v", tt.expectedResult, result) + } + }) + } } func TestVideoAuctionResponseHeaders(t *testing.T) { diff --git a/errortypes/code.go b/errortypes/code.go index 0b194d0830..47e5292257 100644 --- a/errortypes/code.go +++ b/errortypes/code.go @@ -37,6 +37,8 @@ const ( SecBrowsingTopicsWarningCode InvalidUserEIDsWarningCode InvalidUserUIDsWarningCode + TooLongTargetingPrefixWarningCode + TooShortTargetingPrefixWarningCode ) // Coder provides an error or warning code with severity. diff --git a/exchange/exchange.go b/exchange/exchange.go index 4fd35279f2..fcf12cad10 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -14,9 +14,6 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adservertargeting" "github.com/prebid/prebid-server/v3/bidadjustment" @@ -33,7 +30,9 @@ import ( "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/ortb" "github.com/prebid/prebid-server/v3/prebid_cache_client" + "github.com/prebid/prebid-server/v3/privacy" "github.com/prebid/prebid-server/v3/stored_requests" "github.com/prebid/prebid-server/v3/stored_responses" "github.com/prebid/prebid-server/v3/usersync" @@ -269,11 +268,15 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog cacheInstructions := getExtCacheInstructions(requestExtPrebid) - targData := getExtTargetData(requestExtPrebid, cacheInstructions) + targData, warning := getExtTargetData(requestExtPrebid, cacheInstructions, r.Account) if targData != nil { _, targData.cacheHost, targData.cachePath = e.cache.GetExtCacheData() } + for _, w := range warning { + r.Warnings = append(r.Warnings, w) + } + // Get currency rates conversions for the auction conversions := currency.GetAuctionCurrencyRates(e.currencyConverter, requestExtPrebid.CurrencyConversions) diff --git a/exchange/targeting.go b/exchange/targeting.go index 4f48d70c16..0a689e4a32 100644 --- a/exchange/targeting.go +++ b/exchange/targeting.go @@ -9,6 +9,8 @@ import ( ) const MaxKeyLength = 20 +const MinKeyLength = 12 // longest attribute length without prefix +const DefaultKeyPrefix = "hb" // targetData tracks information about the winning Bid in each Imp. // @@ -30,6 +32,7 @@ type targetData struct { // cacheHost and cachePath exist to supply cache host and path as targeting parameters cacheHost string cachePath string + prefix string } // setTargeting writes all the targeting params into the bids. @@ -66,38 +69,38 @@ func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMappi targets := make(map[string]string, 10) if cpm, ok := auc.roundedPrices[topBid]; ok { - targData.addKeys(targets, openrtb_ext.HbpbConstantKey, cpm, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.PbKey, cpm, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } - targData.addKeys(targets, openrtb_ext.HbBidderConstantKey, string(targetingBidderCode), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.BidderKey, string(targetingBidderCode), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) if hbSize := makeHbSize(topBid.Bid); hbSize != "" { - targData.addKeys(targets, openrtb_ext.HbSizeConstantKey, hbSize, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.SizeKey, hbSize, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if cacheID, ok := auc.cacheIds[topBid.Bid]; ok { - targData.addKeys(targets, openrtb_ext.HbCacheKey, cacheID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.CacheKey, cacheID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if vastID, ok := auc.vastCacheIds[topBid.Bid]; ok { - targData.addKeys(targets, openrtb_ext.HbVastCacheKey, vastID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.VastCacheKey, vastID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if targData.includeFormat { - targData.addKeys(targets, openrtb_ext.HbFormatKey, string(topBid.BidType), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.FormatKey, string(topBid.BidType), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if targData.cacheHost != "" { - targData.addKeys(targets, openrtb_ext.HbConstantCacheHostKey, targData.cacheHost, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.CacheHostKey, targData.cacheHost, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if targData.cachePath != "" { - targData.addKeys(targets, openrtb_ext.HbConstantCachePathKey, targData.cachePath, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.CachePathKey, targData.cachePath, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if bidHasDeal { - targData.addKeys(targets, openrtb_ext.HbDealIDConstantKey, topBid.Bid.DealID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.DealKey, topBid.Bid.DealID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if isApp { - targData.addKeys(targets, openrtb_ext.HbEnvKey, openrtb_ext.HbEnvKeyApp, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.EnvKey, openrtb_ext.EnvAppValue, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if len(categoryMapping) > 0 { - targData.addKeys(targets, openrtb_ext.HbCategoryDurationKey, categoryMapping[topBid.Bid.ID], targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + targData.addKeys(targets, openrtb_ext.CategoryDurationKey, categoryMapping[topBid.Bid.ID], targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } topBid.BidTargets = targets } @@ -106,20 +109,15 @@ func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMappi } func (targData *targetData) addKeys(keys map[string]string, key openrtb_ext.TargetingKey, value string, bidderName openrtb_ext.BidderName, overallWinner bool, truncateTargetAttr *int, bidHasDeal bool) { - var maxLength int - if truncateTargetAttr != nil { + maxLength := MaxKeyLength + if truncateTargetAttr != nil && *truncateTargetAttr > 0 { maxLength = *truncateTargetAttr - if maxLength < 0 { - maxLength = MaxKeyLength - } - } else { - maxLength = MaxKeyLength } if targData.includeBidderKeys || (targData.alwaysIncludeDeals && bidHasDeal) { - keys[key.BidderKey(bidderName, maxLength)] = value + keys[key.BidderKey(targData.prefix, bidderName, maxLength)] = value } if targData.includeWinners && overallWinner { - keys[key.TruncateKey(maxLength)] = value + keys[key.TruncateKey(targData.prefix, maxLength)] = value } } diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index 8bfe67475d..c77239e998 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -46,26 +46,71 @@ var mockBids = map[openrtb_ext.BidderName][]*openrtb2.Bid{ // Prevents #378. This is not a JSON test because the cache ID values aren't reproducible, which makes them a pain to test in that format. func TestTargetingCache(t *testing.T) { - bids := runTargetingAuction(t, mockBids, true, true, true, false) + bids := runTargetingAuction(t, mockBids, true, true, true, false, "", "") // Make sure that the cache keys exist on the bids where they're expected to - assertKeyExists(t, bids["winning-bid"], string(openrtb_ext.HbCacheKey), true) - assertKeyExists(t, bids["winning-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, MaxKeyLength), true) + assertKeyExists(t, bids["winning-bid"], DefaultKeyPrefix+string(openrtb_ext.CacheKey), true) + assertKeyExists(t, bids["winning-bid"], openrtb_ext.CacheKey.BidderKey(DefaultKeyPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), true) - assertKeyExists(t, bids["contending-bid"], string(openrtb_ext.HbCacheKey), false) - assertKeyExists(t, bids["contending-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderRubicon, MaxKeyLength), true) + assertKeyExists(t, bids["contending-bid"], DefaultKeyPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["contending-bid"], openrtb_ext.CacheKey.BidderKey(DefaultKeyPrefix, openrtb_ext.BidderRubicon, MaxKeyLength), true) - assertKeyExists(t, bids["losing-bid"], string(openrtb_ext.HbCacheKey), false) - assertKeyExists(t, bids["losing-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, MaxKeyLength), false) + assertKeyExists(t, bids["losing-bid"], DefaultKeyPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["losing-bid"], openrtb_ext.CacheKey.BidderKey(DefaultKeyPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), false) //assert hb_cache_host was included - assert.Contains(t, string(bids["winning-bid"].Ext), string(openrtb_ext.HbConstantCacheHostKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), DefaultKeyPrefix+string(openrtb_ext.CacheHostKey)) assert.Contains(t, string(bids["winning-bid"].Ext), "www.pbcserver.com") //assert hb_cache_path was included - assert.Contains(t, string(bids["winning-bid"].Ext), string(openrtb_ext.HbConstantCachePathKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), DefaultKeyPrefix+string(openrtb_ext.CachePathKey)) assert.Contains(t, string(bids["winning-bid"].Ext), "/pbcache/endpoint") +} + +func TestTargetingCacheRequestPrefix(t *testing.T) { + reqPrefix := "req" + bids := runTargetingAuction(t, mockBids, true, true, true, false, reqPrefix, "acc") + + // Make sure that the cache keys exist on the bids where they're expected to + assertKeyExists(t, bids["winning-bid"], reqPrefix+string(openrtb_ext.CacheKey), true) + assertKeyExists(t, bids["winning-bid"], openrtb_ext.CacheKey.BidderKey(reqPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), true) + + assertKeyExists(t, bids["contending-bid"], reqPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["contending-bid"], openrtb_ext.CacheKey.BidderKey(reqPrefix, openrtb_ext.BidderRubicon, MaxKeyLength), true) + + assertKeyExists(t, bids["losing-bid"], reqPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["losing-bid"], openrtb_ext.CacheKey.BidderKey(reqPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), false) + + //assert hb_cache_host was included + assert.Contains(t, string(bids["winning-bid"].Ext), reqPrefix+string(openrtb_ext.CacheHostKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), "www.pbcserver.com") + + //assert hb_cache_path was included + assert.Contains(t, string(bids["winning-bid"].Ext), reqPrefix+string(openrtb_ext.CachePathKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), "/pbcache/endpoint") +} + +func TestTargetingCacheAccountPrefix(t *testing.T) { + accPrefix := "acc" + bids := runTargetingAuction(t, mockBids, true, true, true, false, "", accPrefix) + + // Make sure that the cache keys exist on the bids where they're expected to + assertKeyExists(t, bids["winning-bid"], accPrefix+string(openrtb_ext.CacheKey), true) + assertKeyExists(t, bids["winning-bid"], openrtb_ext.CacheKey.BidderKey(accPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), true) + + assertKeyExists(t, bids["contending-bid"], accPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["contending-bid"], openrtb_ext.CacheKey.BidderKey(accPrefix, openrtb_ext.BidderRubicon, MaxKeyLength), true) + assertKeyExists(t, bids["losing-bid"], accPrefix+string(openrtb_ext.CacheKey), false) + assertKeyExists(t, bids["losing-bid"], openrtb_ext.CacheKey.BidderKey(accPrefix, openrtb_ext.BidderAppnexus, MaxKeyLength), false) + + //assert hb_cache_host was included + assert.Contains(t, string(bids["winning-bid"].Ext), accPrefix+string(openrtb_ext.CacheHostKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), "www.pbcserver.com") + + //assert hb_cache_path was included + assert.Contains(t, string(bids["winning-bid"].Ext), accPrefix+string(openrtb_ext.CachePathKey)) + assert.Contains(t, string(bids["winning-bid"].Ext), "/pbcache/endpoint") } func assertKeyExists(t *testing.T, bid *openrtb2.Bid, key string, expected bool) { @@ -78,7 +123,7 @@ func assertKeyExists(t *testing.T, bid *openrtb2.Bid, key string, expected bool) // runAuction takes a bunch of mock bids by Bidder and runs an auction. It returns a map of Bids indexed by their ImpID. // If includeCache is true, the auction will be run with cacheing as well, so the cache targeting keys should exist. -func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*openrtb2.Bid, includeCache bool, includeWinners bool, includeBidderKeys bool, isApp bool) map[string]*openrtb2.Bid { +func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*openrtb2.Bid, includeCache bool, includeWinners bool, includeBidderKeys bool, isApp bool, requestPrefix string, accountPrefix string) map[string]*openrtb2.Bid { server := httptest.NewServer(http.HandlerFunc(mockServer)) defer server.Close() @@ -113,7 +158,7 @@ func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*op req := &openrtb2.BidRequest{ Imp: imps, - Ext: buildTargetingExt(includeCache, includeWinners, includeBidderKeys), + Ext: buildTargetingExt(includeCache, includeWinners, includeBidderKeys, requestPrefix), } if isApp { req.App = &openrtb2.App{} @@ -123,10 +168,12 @@ func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*op auctionRequest := &AuctionRequest{ BidRequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: req}, - Account: config.Account{}, - UserSyncs: &emptyUsersync{}, - HookExecutor: &hookexecution.EmptyHookExecutor{}, - TCF2Config: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), + Account: config.Account{ + TargetingPrefix: accountPrefix, + }, + UserSyncs: &emptyUsersync{}, + HookExecutor: &hookexecution.EmptyHookExecutor{}, + TCF2Config: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), } debugLog := DebugLog{} @@ -153,16 +200,16 @@ func buildAdapterMap(bids map[openrtb_ext.BidderName][]*openrtb2.Bid, mockServer return adapterMap } -func buildTargetingExt(includeCache bool, includeWinners bool, includeBidderKeys bool) json.RawMessage { +func buildTargetingExt(includeCache bool, includeWinners bool, includeBidderKeys bool, prefix string) json.RawMessage { var targeting string if includeWinners && includeBidderKeys { - targeting = `{"pricegranularity":{"precision":2,"ranges": [{"min": 0,"max": 20,"increment": 0.1}]},"includewinners": true, "includebidderkeys": true}` + targeting = `{"prefix":"` + prefix + `","pricegranularity":{"precision":2,"ranges": [{"min": 0,"max": 20,"increment": 0.1}]},"includewinners": true, "includebidderkeys": true}` } else if !includeWinners && includeBidderKeys { - targeting = `{"precision":2,"includewinners": false}` + targeting = `{"prefix":"` + prefix + `","precision":2,"includewinners": false}` } else if includeWinners && !includeBidderKeys { - targeting = `{"precision":2,"includebidderkeys": false}` + targeting = `{"prefix":"` + prefix + `","precision":2,"includebidderkeys": false}` } else { - targeting = `{"precision":2,"includewinners": false, "includebidderkeys": false}` + targeting = `{"prefix":"` + prefix + `","precision":2,"includewinners": false, "includebidderkeys": false}` } if includeCache { @@ -342,6 +389,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeWinners: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -377,6 +425,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeBidderKeys: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -419,6 +468,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), alwaysIncludeDeals: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -469,6 +519,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ includeWinners: true, includeBidderKeys: true, includeFormat: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -518,6 +569,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ includeBidderKeys: true, cacheHost: "cache.prebid.com", cachePath: "cache", + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -566,11 +618,68 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ }, TruncateTargetAttr: nil, }, + { + Description: "Cache and deal targeting test custom prefix", + TargetData: targetData{ + priceGranularity: lookupPriceGranularity("med"), + includeBidderKeys: true, + cacheHost: "cache.prebid.com", + cachePath: "cache", + prefix: "prefix", + }, + Auction: auction{ + allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: {{ + Bid: bid123, + BidType: openrtb_ext.BidTypeBanner, + }}, + openrtb_ext.BidderRubicon: {{ + Bid: bid111, + BidType: openrtb_ext.BidTypeBanner, + }}, + }, + }, + cacheIds: map[*openrtb2.Bid]string{ + bid123: "55555", + bid111: "cacheme", + }, + }, + ExpectedPbsBids: map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "prefix_bidder_appnex": "appnexus", + "prefix_pb_appnexus": "1.20", + "prefix_cache_id_appn": "55555", + "prefix_cache_host_ap": "cache.prebid.com", + "prefix_cache_path_ap": "cache", + }, + }, + }, + openrtb_ext.BidderRubicon: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "prefix_bidder_rubico": "rubicon", + "prefix_pb_rubicon": "1.10", + "prefix_cache_id_rubi": "cacheme", + "prefix_deal_rubicon": "mydeal", + "prefix_cache_host_ru": "cache.prebid.com", + "prefix_cache_path_ru": "cache", + }, + }, + }, + }, + }, + TruncateTargetAttr: nil, + }, { Description: "bidder with no dealID should not have deal targeting", TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeBidderKeys: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -601,6 +710,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeBidderKeys: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -643,6 +753,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeBidderKeys: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -685,6 +796,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeBidderKeys: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -727,6 +839,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeWinners: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -762,6 +875,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeWinners: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -797,6 +911,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ TargetData: targetData{ priceGranularity: lookupPriceGranularity("med"), includeWinners: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ @@ -834,6 +949,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ includeWinners: true, includeBidderKeys: true, includeFormat: true, + prefix: DefaultKeyPrefix, }, Auction: auction{ allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ diff --git a/exchange/utils.go b/exchange/utils.go index 415ded1307..08ea0186df 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -925,8 +925,9 @@ func getExtCacheInstructions(requestExtPrebid *openrtb_ext.ExtRequestPrebid) ext return cacheInstructions } -func getExtTargetData(requestExtPrebid *openrtb_ext.ExtRequestPrebid, cacheInstructions extCacheInstructions) *targetData { +func getExtTargetData(requestExtPrebid *openrtb_ext.ExtRequestPrebid, cacheInstructions extCacheInstructions, account config.Account) (*targetData, []*errortypes.Warning) { if requestExtPrebid != nil && requestExtPrebid.Targeting != nil { + prefix, warning := getTargetDataPrefix(requestExtPrebid.Targeting.Prefix, account) return &targetData{ alwaysIncludeDeals: requestExtPrebid.Targeting.AlwaysIncludeDeals, includeBidderKeys: ptrutil.ValueOrDefault(requestExtPrebid.Targeting.IncludeBidderKeys), @@ -937,10 +938,49 @@ func getExtTargetData(requestExtPrebid *openrtb_ext.ExtRequestPrebid, cacheInstr mediaTypePriceGranularity: ptrutil.ValueOrDefault(requestExtPrebid.Targeting.MediaTypePriceGranularity), preferDeals: requestExtPrebid.Targeting.PreferDeals, priceGranularity: ptrutil.ValueOrDefault(requestExtPrebid.Targeting.PriceGranularity), + prefix: prefix, + }, warning + } + + return nil, nil +} + +func getTargetDataPrefix(requestPrefix string, account config.Account) (string, []*errortypes.Warning) { + var warnings []*errortypes.Warning + + maxLength := MaxKeyLength + if account.TruncateTargetAttribute != nil { + if *account.TruncateTargetAttribute > MinKeyLength { + maxLength = *account.TruncateTargetAttribute + } + + if *account.TruncateTargetAttribute < MinKeyLength { + warnings = append(warnings, &errortypes.Warning{ + WarningCode: errortypes.TooShortTargetingPrefixWarningCode, + Message: "targeting prefix is shorter than 'MinKeyLength' value: increase prefix length", + }) + return DefaultKeyPrefix, warnings } } - return nil + maxLength -= MinKeyLength + result := DefaultKeyPrefix + + if requestPrefix != "" { + result = requestPrefix + } else if account.TargetingPrefix != "" { + result = account.TargetingPrefix + } + + if len(result) > maxLength { + warnings = append(warnings, &errortypes.Warning{ + WarningCode: errortypes.TooLongTargetingPrefixWarningCode, + Message: "targeting prefix combined with key attribute is longer than 'settings.targeting.truncate-attr-chars' value: decrease prefix length or increase truncate-attr-chars", + }) + return DefaultKeyPrefix, warnings + } + + return result, warnings } // getDebugInfo returns the boolean flags that allow for debug information in bidResponse.Ext, the SeatBid.httpcalls slice, and diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 676609cd4b..2898e52b2a 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -1981,18 +1981,24 @@ func TestGetExtTargetData(t *testing.T) { name string givenRequestExtPrebid *openrtb_ext.ExtRequestPrebid givenCacheInstructions extCacheInstructions + givenAccount config.Account + givenWarning []*errortypes.Warning expectTargetData *targetData }{ { name: "nil", givenRequestExtPrebid: nil, givenCacheInstructions: extCacheInstructions{cacheBids: true, cacheVAST: true}, + givenAccount: config.Account{}, + givenWarning: nil, expectTargetData: nil, }, { name: "nil-targeting", givenRequestExtPrebid: &openrtb_ext.ExtRequestPrebid{Targeting: nil}, givenCacheInstructions: extCacheInstructions{cacheBids: true, cacheVAST: true}, + givenAccount: config.Account{}, + givenWarning: nil, expectTargetData: nil, }, { @@ -2015,6 +2021,8 @@ func TestGetExtTargetData(t *testing.T) { cacheBids: true, cacheVAST: true, }, + givenAccount: config.Account{}, + givenWarning: nil, expectTargetData: &targetData{ alwaysIncludeDeals: true, includeBidderKeys: true, @@ -2028,6 +2036,7 @@ func TestGetExtTargetData(t *testing.T) { Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Min: 0.00, Max: 5.00, Increment: 1.00}}, }, + prefix: DefaultKeyPrefix, }, }, { @@ -2047,6 +2056,8 @@ func TestGetExtTargetData(t *testing.T) { cacheBids: true, cacheVAST: true, }, + givenAccount: config.Account{}, + givenWarning: nil, expectTargetData: &targetData{ alwaysIncludeDeals: true, includeBidderKeys: false, @@ -2057,13 +2068,15 @@ func TestGetExtTargetData(t *testing.T) { mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{}, preferDeals: true, priceGranularity: openrtb_ext.PriceGranularity{}, + prefix: DefaultKeyPrefix, }, }, } for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - result := getExtTargetData(test.givenRequestExtPrebid, test.givenCacheInstructions) + result, warnings := getExtTargetData(test.givenRequestExtPrebid, test.givenCacheInstructions, test.givenAccount) + assert.Equal(t, test.givenWarning, warnings) assert.Equal(t, test.expectTargetData, result) }) } @@ -4140,6 +4153,65 @@ func TestCleanOpenRTBRequestsFilterBidderRequestExt(t *testing.T) { } } +func TestGetTargetDataPrefix(t *testing.T) { + testCases := []struct { + description string + requestPrefix string + account config.Account + expectedResult string + expectedWarnings int + }{ + { + description: "TruncateTargetAttribute set is nil", + requestPrefix: "", + account: config.Account{ + TargetingPrefix: "hb", + TruncateTargetAttribute: nil, + }, + expectedResult: "hb", + expectedWarnings: 0, + }, + { + description: "TargetingPrefix set in Account", + requestPrefix: "tst", + account: config.Account{ + TargetingPrefix: "tst", + TruncateTargetAttribute: intPtr(15), + }, + expectedResult: "tst", + expectedWarnings: 0, + }, + { + description: "TargetingPrefix is longer than expected", + requestPrefix: "test", + account: config.Account{ + TargetingPrefix: "test", + TruncateTargetAttribute: intPtr(15), + }, + expectedResult: "hb", + expectedWarnings: 1, + }, + { + description: "TruncateTargetAttribute is smaller than expected", + requestPrefix: "test", + account: config.Account{ + TargetingPrefix: "test", + TruncateTargetAttribute: intPtr(1), + }, + expectedResult: "hb", + expectedWarnings: 1, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + result, warnings := getTargetDataPrefix(tc.requestPrefix, tc.account) + assert.Equal(t, tc.expectedResult, result) + assert.Len(t, warnings, tc.expectedWarnings) + }) + } +} + type GPPMockSection struct { sectionID constants.SectionID value string @@ -5782,3 +5854,7 @@ func TestExtractAndCleanBuyerUIDs(t *testing.T) { }) } } + +func intPtr(i int) *int { + return &i +} diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go index 526c3bb3f3..9856df241f 100644 --- a/openrtb_ext/bid.go +++ b/openrtb_ext/bid.go @@ -139,40 +139,40 @@ func ParseBidType(bidType string) (BidType, error) { type TargetingKey string const ( - HbpbConstantKey TargetingKey = "hb_pb" + PbKey TargetingKey = "_pb" - // HbEnvKey exists to support the Prebid Universal Creative. If it exists, the only legal value is mobile-app. + // EnvKey exists to support the Prebid Universal Creative. If it exists, the only legal value is mobile-app. // It will exist only if the incoming bidRequest defined request.app instead of request.site. - HbEnvKey TargetingKey = "hb_env" + EnvKey TargetingKey = "_env" - // HbCacheHost and HbCachePath exist to supply cache host and path as targeting parameters - HbConstantCacheHostKey TargetingKey = "hb_cache_host" - HbConstantCachePathKey TargetingKey = "hb_cache_path" + // CacheHostKey and CachePathKey exist to supply cache host and path as targeting parameters + CacheHostKey TargetingKey = "_cache_host" + CachePathKey TargetingKey = "_cache_path" - // HbBidderConstantKey is the name of the Bidder. For example, "appnexus" or "rubicon". - HbBidderConstantKey TargetingKey = "hb_bidder" - HbSizeConstantKey TargetingKey = "hb_size" - HbDealIDConstantKey TargetingKey = "hb_deal" + // BidderKey is the name of the Bidder. For example, "appnexus" or "rubicon". + BidderKey TargetingKey = "_bidder" + SizeKey TargetingKey = "_size" + DealKey TargetingKey = "_deal" - // HbFormatKey is the format of the bid. For example, "video", "banner" - HbFormatKey TargetingKey = "hb_format" + // FormatKey is the format of the bid. For example, "video", "banner" + FormatKey TargetingKey = "_format" - // HbCacheKey and HbVastCacheKey store UUIDs which can be used to fetch things from prebid cache. + // CacheKey and VastCacheKey store UUIDs which can be used to fetch things from prebid cache. // Callers should *never* assume that either of these exist, since the call to the cache may always fail. // - // HbVastCacheKey's UUID will fetch the entire bid JSON, while HbVastCacheKey will fetch just the VAST XML. - // HbVastCacheKey will only ever exist for Video bids. - HbCacheKey TargetingKey = "hb_cache_id" - HbVastCacheKey TargetingKey = "hb_uuid" + // VastCacheKey's UUID will fetch the entire bid JSON, while VastCacheKey will fetch just the VAST XML. + // VastCacheKey will only ever exist for Video bids. + CacheKey TargetingKey = "_cache_id" + VastCacheKey TargetingKey = "_uuid" - // This is not a key, but values used by the HbEnvKey - HbEnvKeyApp string = "mobile-app" + // EnvAppValue used as a value for EnvKey + EnvAppValue string = "mobile-app" - HbCategoryDurationKey TargetingKey = "hb_pb_cat_dur" + CategoryDurationKey TargetingKey = "_pb_cat_dur" ) -func (key TargetingKey) BidderKey(bidder BidderName, maxLength int) string { - s := string(key) + "_" + string(bidder) +func (key TargetingKey) BidderKey(prefix string, bidder BidderName, maxLength int) string { + s := prefix + string(key) + "_" + string(bidder) if maxLength != 0 { return s[:min(len(s), maxLength)] } @@ -186,11 +186,12 @@ func min(x, y int) int { return y } -func (key TargetingKey) TruncateKey(maxLength int) string { +func (key TargetingKey) TruncateKey(prefix string, maxLength int) string { + result := prefix + string(key) if maxLength > 0 { - return string(key)[:min(len(string(key)), maxLength)] + return result[:min(len(result), maxLength)] } - return string(key) + return result } const ( diff --git a/openrtb_ext/bid_test.go b/openrtb_ext/bid_test.go index aebc1d686d..b0326d7562 100644 --- a/openrtb_ext/bid_test.go +++ b/openrtb_ext/bid_test.go @@ -7,14 +7,14 @@ import ( ) func TestBidderKey(t *testing.T) { - apnKey := HbpbConstantKey.BidderKey(BidderAppnexus, 50) + apnKey := PbKey.BidderKey("hb", BidderAppnexus, 50) if apnKey != "hb_pb_appnexus" { t.Errorf("Bad resolved targeting key. Expected hb_pb_appnexus, got %s", apnKey) } } func TestTruncatedKey(t *testing.T) { - apnKey := HbpbConstantKey.BidderKey(BidderAppnexus, 8) + apnKey := PbKey.BidderKey("hb", BidderAppnexus, 8) if apnKey != "hb_pb_ap" { t.Errorf("Bad truncated targeting key. Expected hb_pb_ap, got %s", apnKey) } @@ -30,25 +30,25 @@ func TestTruncateKey(t *testing.T) { { description: "Targeting key is smaller than max length, expect targeting key to stay the same", givenMaxLength: 15, - givenTargetingKey: TargetingKey("hb_bidder_key"), + givenTargetingKey: TargetingKey("_bidder_key"), expectedTargetingKey: "hb_bidder_key", }, { description: "Targeting key is larger than max length, expect targeting key to be truncated", givenMaxLength: 9, - givenTargetingKey: TargetingKey("hb_bidder_key"), + givenTargetingKey: TargetingKey("_bidder_key"), expectedTargetingKey: "hb_bidder", }, { description: "Max length isn't greater than zero, expect targeting key to not be truncated", givenMaxLength: 0, - givenTargetingKey: TargetingKey("hb_bidder_key"), + givenTargetingKey: TargetingKey("_bidder_key"), expectedTargetingKey: "hb_bidder_key", }, } for _, test := range testCases { - truncatedKey := test.givenTargetingKey.TruncateKey(test.givenMaxLength) + truncatedKey := test.givenTargetingKey.TruncateKey("hb", test.givenMaxLength) assert.Equalf(t, test.expectedTargetingKey, truncatedKey, "The Targeting Key is incorrect: %s\n", test.description) } } diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go index f3fb043869..7f8978e6eb 100644 --- a/openrtb_ext/request.go +++ b/openrtb_ext/request.go @@ -204,6 +204,7 @@ type ExtRequestTargeting struct { PreferDeals bool `json:"preferdeals,omitempty"` AppendBidderNames bool `json:"appendbiddernames,omitempty"` AlwaysIncludeDeals bool `json:"alwaysincludedeals,omitempty"` + Prefix string `json:"prefix,omitempty"` } type ExtIncludeBrandCategory struct { @@ -493,6 +494,7 @@ func (erp *ExtRequestPrebid) Clone() *ExtRequestPrebid { DurationRangeSec: slices.Clone(erp.Targeting.DurationRangeSec), PreferDeals: erp.Targeting.PreferDeals, AppendBidderNames: erp.Targeting.AppendBidderNames, + Prefix: erp.Targeting.Prefix, } if erp.Targeting.PriceGranularity != nil { newPriceGranularity := &PriceGranularity{ From b7c6bcfab6d7f42d583a77c194a694c1f73a7aa3 Mon Sep 17 00:00:00 2001 From: pm-priyanka-bagade <156899734+pm-priyanka-bagade@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:46:43 +0530 Subject: [PATCH 012/272] Pubmatic: Set bid.meta.mediaType=video when bid.ext.ibv=true (#4189) --- adapters/pubmatic/pubmatic.go | 51 +++-- adapters/pubmatic/pubmatic_test.go | 162 ++++++++++---- .../pubmatictest/exemplary/banner.json | 5 +- .../pubmatictest/exemplary/fledge.json | 5 +- .../pubmatictest/exemplary/native.json | 5 +- .../pubmatictest/exemplary/video.json | 3 +- .../pubmatictest/supplemental/app.json | 5 +- .../supplemental/bid_ext_ibv_true.json | 200 ++++++++++++++++++ .../supplemental/dctrAndPmZoneID.json | 5 +- .../supplemental/displayManagerInAppExt.json | 5 +- .../displayManagerInAppExtPrebid.json | 5 +- .../pubmatictest/supplemental/extra-bid.json | 8 +- .../supplemental/gptSlotNameInImpExt.json | 5 +- .../gptSlotNameInImpExtPbAdslot.json | 5 +- .../pubmatictest/supplemental/impExt.json | 5 +- .../supplemental/multiplemedia.json | 5 +- .../supplemental/native_invalid_adm.json | 5 +- .../pubmatictest/supplemental/nilReqExt.json | 5 +- .../pubmatictest/supplemental/noAdSlot.json | 5 +- .../supplemental/pmZoneIDInKeywords.json | 5 +- .../supplemental/reqBidderParams.json | 5 +- .../supplemental/trimPublisherID.json | 5 +- 22 files changed, 407 insertions(+), 102 deletions(-) create mode 100644 adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index ef6354b7bb..9c42ae57b2 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -30,10 +30,10 @@ type PubmaticAdapter struct { } type pubmaticBidExt struct { - BidType *int `json:"BidType,omitempty"` VideoCreativeInfo *pubmaticBidExtVideo `json:"video,omitempty"` Marketplace string `json:"marketplace,omitempty"` PrebidDealPriority int `json:"prebiddealpriority,omitempty"` + InBannerVideo bool `json:"ibv,omitempty"` } type pubmaticWrapperExt struct { @@ -461,19 +461,24 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa bid.Cat = bid.Cat[0:1] } + mType, err := getMediaTypeForBid(&bid) + if err != nil { + errs = append(errs, err) + continue + } + typedBid := &adapters.TypedBid{ Bid: &bid, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, } var bidExt *pubmaticBidExt - err := jsonutil.Unmarshal(bid.Ext, &bidExt) + err = jsonutil.Unmarshal(bid.Ext, &bidExt) if err != nil { errs = append(errs, err) } else if bidExt != nil { typedBid.Seat = openrtb_ext.BidderName(bidExt.Marketplace) - typedBid.BidType = getBidType(bidExt) + if bidExt.PrebidDealPriority > 0 { typedBid.DealPriority = bidExt.PrebidDealPriority } @@ -481,9 +486,14 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa if bidExt.VideoCreativeInfo != nil && bidExt.VideoCreativeInfo.Duration != nil { typedBid.BidVideo.Duration = *bidExt.VideoCreativeInfo.Duration } + + typedBid.BidMeta = &openrtb_ext.ExtBidPrebidMeta{MediaType: string(mType)} + if bidExt.InBannerVideo { + typedBid.BidMeta.MediaType = string(openrtb_ext.BidTypeVideo) + } } - if typedBid.BidType == openrtb_ext.BidTypeNative { + if mType == openrtb_ext.BidTypeNative { bid.AdM, err = getNativeAdm(bid.AdM) if err != nil { errs = append(errs, err) @@ -637,24 +647,27 @@ func getStringArray(array []interface{}) []string { return aString } -// getBidType returns the bid type specified in the response bid.ext -func getBidType(bidExt *pubmaticBidExt) openrtb_ext.BidType { +// getMediaTypeForBid returns the Mtype +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { // setting "banner" as the default bid type - bidType := openrtb_ext.BidTypeBanner - if bidExt != nil && bidExt.BidType != nil { - switch *bidExt.BidType { - case 0: - bidType = openrtb_ext.BidTypeBanner - case 1: - bidType = openrtb_ext.BidTypeVideo - case 2: - bidType = openrtb_ext.BidTypeNative + mType := openrtb_ext.BidTypeBanner + if bid != nil { + switch bid.MType { + case openrtb2.MarkupBanner: + mType = openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + mType = openrtb_ext.BidTypeVideo + case openrtb2.MarkupAudio: + mType = openrtb_ext.BidTypeAudio + case openrtb2.MarkupNative: + mType = openrtb_ext.BidTypeNative default: - // default value is banner - bidType = openrtb_ext.BidTypeBanner + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("failed to parse bid mtype (%d) for impression id %s", bid.MType, bid.ImpID), + } } } - return bidType + return mType, nil } // Builder builds a new instance of the Pubmatic adapter for the given bidder with the given config. diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go index 122840771b..74883b23a9 100644 --- a/adapters/pubmatic/pubmatic_test.go +++ b/adapters/pubmatic/pubmatic_test.go @@ -11,8 +11,10 @@ import ( "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestJsonSamples(t *testing.T) { @@ -26,52 +28,67 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "pubmatictest", bidder) } -func TestGetBidTypeVideo(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 1 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeVideo { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeVideo, actualBidTypeValue) +func TestGetMediaTypeForBid(t *testing.T) { + tests := []struct { + name string + mType openrtb2.MarkupType + expectedMType openrtb_ext.BidType + expectedError error + }{ + { + name: "Test Banner Bid Type", + mType: 1, + expectedMType: openrtb_ext.BidTypeBanner, + expectedError: nil, + }, + { + name: "Test Video Bid Type", + mType: 2, + expectedMType: openrtb_ext.BidTypeVideo, + expectedError: nil, + }, + { + name: "Test Audio Bid Type", + mType: 3, + expectedMType: openrtb_ext.BidTypeAudio, + expectedError: nil, + }, + { + name: "Test Native Bid Type", + mType: 4, + expectedMType: openrtb_ext.BidTypeNative, + expectedError: nil, + }, + { + name: "Test Unsupported MType (Invalid MType)", + mType: 44, + expectedMType: "", // default value for unsupported types + expectedError: &errortypes.BadServerResponse{Message: "failed to parse bid mtype (44) for impression id "}, + }, + { + name: "Test Default MType (MType 0 or Not Set)", + mType: 0, // This represents the default case where MType is not explicitly set + expectedMType: "", // Default is empty and return error + expectedError: &errortypes.BadServerResponse{Message: "failed to parse bid mtype (0) for impression id "}, + }, } -} -func TestGetBidTypeForMissingBidTypeExt(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - actualBidTypeValue := getBidType(pubmaticExt) - // banner is the default bid type when no bidType key is present in the bid.ext - if actualBidTypeValue != "banner" { - t.Errorf("Expected Bid Type value was: banner, actual value is: %v", actualBidTypeValue) - } -} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bid := openrtb2.Bid{ + MType: tt.mType, + } -func TestGetBidTypeBanner(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 0 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeBanner { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue) - } -} + actualBidTypeValue, actualError := getMediaTypeForBid(&bid) -func TestGetBidTypeNative(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 2 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeNative { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeNative, actualBidTypeValue) - } -} + assert.Equal(t, tt.expectedMType, actualBidTypeValue, "unexpected BidType value") -func TestGetBidTypeForUnsupportedCode(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 99 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeBanner { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue) + if tt.expectedError != nil { + require.EqualError(t, actualError, tt.expectedError.Error(), "unexpected error message") + return + } + require.NoError(t, actualError, "expected no error but got one") + }) } } @@ -398,7 +415,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { args: args{ response: &adapters.ResponseData{ StatusCode: http.StatusOK, - Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), }, }, wantErr: nil, @@ -416,11 +433,14 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { H: 250, W: 300, DealID: "testdeal", + MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}`), }, DealPriority: 1, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "banner", + }, }, }, Currency: "USD", @@ -431,7 +451,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { args: args{ response: &adapters.ResponseData{ StatusCode: http.StatusOK, - Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal","mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), }, }, wantErr: nil, @@ -449,15 +469,67 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { H: 250, W: 300, DealID: "testdeal", + MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}`), }, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "banner", + }, }, }, Currency: "USD", }, }, + { + name: "bid_ext_InBannerVideo_is_true", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: nil, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "7706636740145184841", + ImpID: "test-imp-id", + Price: 0.500000, + AdID: "29681110", + AdM: "some-test-ad", + ADomain: []string{"pubmatic.com"}, + CrID: "29681110", + H: 250, + W: 300, + DealID: "testdeal", + MType: 1, + Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}`), + }, + BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "video", + }, + }, + }, + Currency: "USD", + }, + }, + { + name: "getMediaTypeForBid_return_error", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 0, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: []error{&errortypes.BadServerResponse{Message: "failed to parse bid mtype (0) for impression id test-imp-id"}}, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{}, + Currency: "USD", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json index 8e505bd334..43e0fd4ecd 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/banner.json +++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json @@ -111,6 +111,7 @@ "h": 250, "w": 300, "dealid":"test deal", + "mtype": 1, "ext": { "dspid": 6, "deal_channel": 1, @@ -142,13 +143,13 @@ "w": 300, "h": 250, "dealid":"test deal", + "mtype": 1, "ext": { "dspid": 6, "deal_channel": 1, "prebiddealpriority": 1 } - }, - "type": "banner" + } } ] } diff --git a/adapters/pubmatic/pubmatictest/exemplary/fledge.json b/adapters/pubmatic/pubmatictest/exemplary/fledge.json index 96c8f93ca5..b094ea13f8 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/fledge.json +++ b/adapters/pubmatic/pubmatictest/exemplary/fledge.json @@ -67,6 +67,7 @@ "crid": "crid_10", "h": 90, "w": 728, + "mtype": 1, "ext": {} } ] @@ -123,9 +124,9 @@ "crid": "crid_10", "w": 728, "h": 90, + "mtype": 1, "ext": {} - }, - "type": "banner" + } } ], "fledgeauctionconfigs": [ diff --git a/adapters/pubmatic/pubmatictest/exemplary/native.json b/adapters/pubmatic/pubmatictest/exemplary/native.json index dedabf8af4..74e0a58af6 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/native.json +++ b/adapters/pubmatic/pubmatictest/exemplary/native.json @@ -76,6 +76,7 @@ "adid": "some-test-id", "adm": "{\"native\":{\"assets\":[{\"id\":2,\"img\":{\"h\":90,\"url\":\"//ads.pubmatic.com/AdTag/native/728x90.png\",\"w\":728}},{\"data\":{\"value\":\"Sponsored By PubMatic\"},\"id\":4},{\"id\":3,\"img\":{\"h\":90,\"url\":\"//ads.pubmatic.com/AdTag/native/728x90.png\",\"w\":728}},{\"id\":1,\"title\":{\"text\":\"Native Test Title\"}},{\"data\":{\"value\":\"Sponsored By PubMatic\"},\"id\":5}],\"imptrackers\":[\"http://clicktracker.com/AdTag/9bde02d0-6017-11e4-9df7-005056967c35\"],\"jstracker\":\"", + "adomain": [ + "testpage-ad" + ], + "crid": "banner_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "banner" + } + } + } + ] + + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "request-id", + "bids": [ + { + "bid": { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "mtype": 1, + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "banner_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "cur": "EUR" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/exemplary/native.json b/adapters/sparteo/sparteotest/exemplary/native.json new file mode 100644 index 0000000000..2f5b9bcc34 --- /dev/null +++ b/adapters/sparteo/sparteotest/exemplary/native.json @@ -0,0 +1,231 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-native-id", + "native": { + "request": "{\"assets\":[{\"id\":1,\"img\":{\"ext\":{\"image1\":\"image2\"},\"h\": 250,\"mimes\":[\"image\/gif\",\"image\/png\"],\"type\":3,\"w\":300},\"required\":1}]}" + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "publisher": { + "domain": "dev.sparteo.com:4444", + "id": "sparteo" + }, + "page": "https://dev.sparteo.com:4444/page/test/", + "ref": "https://dev.sparteo.com:4444/page/test/" + }, + "device": { + "w": 1920, + "h": 1080, + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + }, + "sua": { + "source": 1, + "platform": { + "brand": "macOS" + }, + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "mobile": 0 + } + }, + "ext": { + "prebid": { + "server": { + "datacenter": "", + "externalurl": "", + "gvlid": 1028 + } + }, + "tmaxmax": 5000 + }, + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-native-id", + "native": { + "request": "{\"assets\":[{\"id\":1,\"img\":{\"ext\":{\"image1\":\"image2\"},\"h\": 250,\"mimes\":[\"image\/gif\",\"image\/png\"],\"type\":3,\"w\":300},\"required\":1}]}" + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "page": "https://dev.sparteo.com:4444/page/test/", + "ref": "https://dev.sparteo.com:4444/page/test/", + "publisher": { + "id": "sparteo", + "domain": "dev.sparteo.com:4444", + "ext": { + "params": { + "networkId": "networkId" + } + } + } + }, + "device": { + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "sua": { + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "platform": { + "brand": "macOS" + }, + "mobile": 0, + "source": 1 + }, + "h": 1080, + "w": 1920, + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + } + }, + "tmax": 5000, + "ext": { + "prebid": { + "server": { + "externalurl": "", + "gvlid": 1028, + "datacenter": "" + } + }, + "tmaxmax": 5000 + } + }, + "impIDs": [ + "div-native-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "request-id", + "seatbid": [ + { + "seat": "sparteo", + "bid": [ + { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-native-id", + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "native_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "native" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "request-id", + "bids": [ + { + "bid": { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-native-id", + "mtype": 4, + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "native_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ], + "cur": "EUR" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/exemplary/video.json b/adapters/sparteo/sparteotest/exemplary/video.json new file mode 100644 index 0000000000..f69d646309 --- /dev/null +++ b/adapters/sparteo/sparteotest/exemplary/video.json @@ -0,0 +1,282 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-video-id", + "video": { + "context": "instream", + "playerSize": [ + 640, + 480 + ], + "mimes": [ + "video/mp4" + ], + "api": [ + 1, + 2, + 7 + ], + "protocols": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "playbackmethod": [ + 2 + ], + "skip": 1, + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "publisher": { + "domain": "dev.sparteo.com:4444", + "id": "sparteo" + }, + "page": "https://dev.sparteo.com:4444/page/test/", + "ref": "https://dev.sparteo.com:4444/page/test/" + }, + "device": { + "w": 1920, + "h": 1080, + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + }, + "sua": { + "source": 1, + "platform": { + "brand": "macOS" + }, + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "mobile": 0 + } + }, + "ext": { + "prebid": { + "server": { + "datacenter": "", + "externalurl": "", + "gvlid": 1028 + } + }, + "tmaxmax": 5000 + }, + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-video-id", + "video": { + "mimes": [ + "video/mp4" + ], + "api": [ + 1, + 2, + 7 + ], + "protocols": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "playbackmethod": [ + 2 + ], + "skip": 1, + "w": 640, + "h": 480 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "page": "https://dev.sparteo.com:4444/page/test/", + "ref": "https://dev.sparteo.com:4444/page/test/", + "publisher": { + "id": "sparteo", + "domain": "dev.sparteo.com:4444", + "ext": { + "params": { + "networkId": "networkId" + } + } + } + }, + "device": { + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "sua": { + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "platform": { + "brand": "macOS" + }, + "mobile": 0, + "source": 1 + }, + "h": 1080, + "w": 1920, + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + } + }, + "tmax": 5000, + "ext": { + "prebid": { + "server": { + "externalurl": "", + "gvlid": 1028, + "datacenter": "" + } + }, + "tmaxmax": 5000 + } + }, + "impIDs": [ + "div-video-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "request-id", + "seatbid": [ + { + "seat": "sparteo", + "bid": [ + { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-video-id", + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "video_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "video" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "request-id", + "bids": [ + { + "bid": { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-video-id", + "mtype": 2, + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "video_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ], + "cur": "EUR" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json b/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json new file mode 100644 index 0000000000..ded36e22d4 --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json @@ -0,0 +1,71 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [ + { + "id": "test-request-id", + "bids": [] + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json b/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json new file mode 100644 index 0000000000..851fcf1860 --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": ["div-banner-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "sparteo", + "bid": [ + { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "price": 0.10797, + "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "testpage-ad" + ], + "crid": "banner_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "foobar" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "test-request-id", + "bids": [] + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json b/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json new file mode 100644 index 0000000000..21e3f35629 --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [ + { + "id": "test-request-id", + "bid": [ + { + "seat": "sparteo", + "bid": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json b/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json new file mode 100644 index 0000000000..61d1d61002 --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": "not an object" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": "not an object" + } + } + ] + }, + "ImpIDs": ["div-banner-id"] + }} + ], + "expectedMakeRequestsErrors": [ + { + "value": "^ignoring imp id=div-banner-id, error while decoding impExt", + "comparison": "regex" + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 0. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json b/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json new file mode 100644 index 0000000000..12ad55425b --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json @@ -0,0 +1,68 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "not a json" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json b/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json new file mode 100644 index 0000000000..5d2bb2148c --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "page": "https://dev.sparteo.com:4444/page/test/", + "ref": "https://dev.sparteo.com:4444/page/test/", + "publisher": { + "id": "sparteo", + "domain": "dev.sparteo.com:4444", + "ext": "not an object" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ], + "site": { + "domain": "dev.sparteo.com:4444", + "page": "https://dev.sparteo.com:4444/page/test/", + "publisher": { + "domain": "dev.sparteo.com:4444", + "ext": { + "params": { + "networkId": "networkId" + } + }, + "id": "sparteo" + }, + "ref": "https://dev.sparteo.com:4444/page/test/" + } + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [ + { + "id": "test-request-id", + "bid": [ + { + "seat": "sparteo", + "bid": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/status_204.json b/adapters/sparteo/sparteotest/supplemental/status_204.json new file mode 100644 index 0000000000..171eec08ed --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/status_204.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/status_400.json b/adapters/sparteo/sparteotest/supplemental/status_400.json new file mode 100644 index 0000000000..26f24b68be --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/status_400.json @@ -0,0 +1,68 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/status_500.json b/adapters/sparteo/sparteotest/supplemental/status_500.json new file mode 100644 index 0000000000..ec3c68e56b --- /dev/null +++ b/adapters/sparteo/sparteotest/supplemental/status_500.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ] + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 751934ac9b..ba0ff57d4a 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -211,6 +211,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/sonobi" "github.com/prebid/prebid-server/v3/adapters/sovrn" "github.com/prebid/prebid-server/v3/adapters/sovrnXsp" + "github.com/prebid/prebid-server/v3/adapters/sparteo" "github.com/prebid/prebid-server/v3/adapters/sspBC" "github.com/prebid/prebid-server/v3/adapters/startio" "github.com/prebid/prebid-server/v3/adapters/stroeerCore" @@ -469,6 +470,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSonobi: sonobi.Builder, openrtb_ext.BidderSovrn: sovrn.Builder, openrtb_ext.BidderSovrnXsp: sovrnXsp.Builder, + openrtb_ext.BidderSparteo: sparteo.Builder, openrtb_ext.BidderSspBC: sspBC.Builder, openrtb_ext.BidderStartIO: startio.Builder, openrtb_ext.BidderStroeerCore: stroeerCore.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 102c9094c3..f43a63a85c 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -229,6 +229,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSonobi, BidderSovrn, BidderSovrnXsp, + BidderSparteo, BidderSspBC, BidderStartIO, BidderStroeerCore, @@ -591,6 +592,7 @@ const ( BidderSonobi BidderName = "sonobi" BidderSovrn BidderName = "sovrn" BidderSovrnXsp BidderName = "sovrnXsp" + BidderSparteo BidderName = "sparteo" BidderSspBC BidderName = "sspBC" BidderStartIO BidderName = "startio" BidderStroeerCore BidderName = "stroeerCore" diff --git a/openrtb_ext/imp_sparteo.go b/openrtb_ext/imp_sparteo.go new file mode 100644 index 0000000000..730cc53598 --- /dev/null +++ b/openrtb_ext/imp_sparteo.go @@ -0,0 +1,10 @@ +package openrtb_ext + +type ExtImpSparteo struct { + NetworkId string `json:"networkId"` + Custom1 string `json:"custom1,omitempty"` + Custom2 string `json:"custom2,omitempty"` + Custom3 string `json:"custom3,omitempty"` + Custom4 string `json:"custom4,omitempty"` + Custom5 string `json:"custom5,omitempty"` +} diff --git a/static/bidder-info/sparteo.yaml b/static/bidder-info/sparteo.yaml new file mode 100644 index 0000000000..1ad61ab072 --- /dev/null +++ b/static/bidder-info/sparteo.yaml @@ -0,0 +1,20 @@ +maintainer: + email: "prebid@sparteo.com" +enabled: true +gvlVendorID: 1028 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +endpoint: "https://bid.sparteo.com/s2s-auction" +userSync: + iframe: + url: "https://sync.sparteo.com/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect_url={{.RedirectURL}}" + supportCors: true \ No newline at end of file diff --git a/static/bidder-params/sparteo.json b/static/bidder-params/sparteo.json new file mode 100644 index 0000000000..2251077647 --- /dev/null +++ b/static/bidder-params/sparteo.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Sparteo Params", + "type": "object", + "properties": { + "networkId": { + "type": "string", + "description": "Sparteo network ID. This information will be given to you by the Sparteo team." + }, + "custom1": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom2": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom3": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom4": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom5": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + } + }, + "required": [ + "networkId" + ], + "additionalProperties": true +} \ No newline at end of file From d07733ae38f8785581e740839e6d5ad86c7f80fd Mon Sep 17 00:00:00 2001 From: Isha Bharti Date: Fri, 4 Jul 2025 00:08:18 +0530 Subject: [PATCH 015/272] PubMatic: Fix missing bid type in bid response (#4417) --- adapters/pubmatic/pubmatic.go | 1 + adapters/pubmatic/pubmatic_test.go | 3 +++ adapters/pubmatic/pubmatictest/exemplary/banner.json | 3 ++- adapters/pubmatic/pubmatictest/exemplary/fledge.json | 3 ++- adapters/pubmatic/pubmatictest/exemplary/native.json | 3 ++- adapters/pubmatic/pubmatictest/exemplary/video.json | 1 + adapters/pubmatic/pubmatictest/supplemental/app.json | 3 ++- .../pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json | 1 + .../pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json | 3 ++- .../pubmatictest/supplemental/displayManagerInAppExt.json | 3 ++- .../supplemental/displayManagerInAppExtPrebid.json | 3 ++- adapters/pubmatic/pubmatictest/supplemental/extra-bid.json | 4 +++- .../pubmatictest/supplemental/gptSlotNameInImpExt.json | 3 ++- .../supplemental/gptSlotNameInImpExtPbAdslot.json | 3 ++- adapters/pubmatic/pubmatictest/supplemental/impExt.json | 3 ++- .../pubmatic/pubmatictest/supplemental/multiplemedia.json | 3 ++- .../pubmatictest/supplemental/native_invalid_adm.json | 3 ++- adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json | 3 ++- adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json | 3 ++- .../pubmatictest/supplemental/pmZoneIDInKeywords.json | 3 ++- .../pubmatic/pubmatictest/supplemental/reqBidderParams.json | 3 ++- .../pubmatic/pubmatictest/supplemental/trimPublisherID.json | 3 ++- 22 files changed, 43 insertions(+), 18 deletions(-) diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index 9c42ae57b2..0126a76d00 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -470,6 +470,7 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa typedBid := &adapters.TypedBid{ Bid: &bid, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidType: mType, } var bidExt *pubmaticBidExt diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go index 74883b23a9..d26754c8c6 100644 --- a/adapters/pubmatic/pubmatic_test.go +++ b/adapters/pubmatic/pubmatic_test.go @@ -437,6 +437,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}`), }, DealPriority: 1, + BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidMeta: &openrtb_ext.ExtBidPrebidMeta{ MediaType: "banner", @@ -472,6 +473,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}`), }, + BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidMeta: &openrtb_ext.ExtBidPrebidMeta{ MediaType: "banner", @@ -507,6 +509,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}`), }, + BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidMeta: &openrtb_ext.ExtBidPrebidMeta{ MediaType: "video", diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json index 43e0fd4ecd..af6c70f112 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/banner.json +++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json @@ -149,7 +149,8 @@ "deal_channel": 1, "prebiddealpriority": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/exemplary/fledge.json b/adapters/pubmatic/pubmatictest/exemplary/fledge.json index b094ea13f8..4dd434b53a 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/fledge.json +++ b/adapters/pubmatic/pubmatictest/exemplary/fledge.json @@ -126,7 +126,8 @@ "h": 90, "mtype": 1, "ext": {} - } + }, + "type": "banner" } ], "fledgeauctionconfigs": [ diff --git a/adapters/pubmatic/pubmatictest/exemplary/native.json b/adapters/pubmatic/pubmatictest/exemplary/native.json index 74e0a58af6..e154ae995e 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/native.json +++ b/adapters/pubmatic/pubmatictest/exemplary/native.json @@ -108,7 +108,8 @@ "deal_channel": 1, "bidtype": 2 } - } + }, + "type": "native" } ] } diff --git a/adapters/pubmatic/pubmatictest/exemplary/video.json b/adapters/pubmatic/pubmatictest/exemplary/video.json index d43b0ac214..c92c97dd31 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/video.json +++ b/adapters/pubmatic/pubmatictest/exemplary/video.json @@ -171,6 +171,7 @@ } } }, + "type": "video", "video" :{ "duration" : 5, "primary_category": "" diff --git a/adapters/pubmatic/pubmatictest/supplemental/app.json b/adapters/pubmatic/pubmatictest/supplemental/app.json index 9c6f61e789..e26b2c3609 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/app.json +++ b/adapters/pubmatic/pubmatictest/supplemental/app.json @@ -133,7 +133,8 @@ "h": 250, "mtype": 1, "dealid":"test deal" - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json b/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json index 531cb651ff..b994a00800 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json +++ b/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json @@ -189,6 +189,7 @@ } } }, + "type": "banner", "video" :{ "duration" : 5, "primary_category": "" diff --git a/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json b/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json index 0bb398841e..2484a78a10 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json +++ b/adapters/pubmatic/pubmatictest/supplemental/dctrAndPmZoneID.json @@ -156,7 +156,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExt.json b/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExt.json index cb19781372..ade3d88db8 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExt.json @@ -168,7 +168,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExtPrebid.json b/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExtPrebid.json index 3f8751d873..b52f1fe70f 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExtPrebid.json +++ b/adapters/pubmatic/pubmatictest/supplemental/displayManagerInAppExtPrebid.json @@ -176,7 +176,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json b/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json index c7214ddd2f..b6f2b53ec1 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json +++ b/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json @@ -182,7 +182,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" }, { "bid": { @@ -203,6 +204,7 @@ "marketplace": "groupm" } }, + "type": "banner", "seat": "groupm" } ] diff --git a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json index 9bdf08764d..03fdcc6ab4 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json @@ -161,7 +161,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json index 2d5933aa5b..6dfffaf2d9 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json +++ b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json @@ -157,7 +157,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/impExt.json b/adapters/pubmatic/pubmatictest/supplemental/impExt.json index 41e3add1a6..707993446a 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/impExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/impExt.json @@ -151,7 +151,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/multiplemedia.json b/adapters/pubmatic/pubmatictest/supplemental/multiplemedia.json index 08a9a08d96..4e456dd58c 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/multiplemedia.json +++ b/adapters/pubmatic/pubmatictest/supplemental/multiplemedia.json @@ -111,7 +111,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json b/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json index ba159e354f..052409415a 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json +++ b/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json @@ -108,7 +108,8 @@ "deal_channel": 1, "bidtype": 2 } - } + }, + "type": "native" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json b/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json index 243e7eeb85..e5a119f9cb 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json @@ -154,7 +154,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json b/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json index ba610e87b1..ff0af3a766 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json +++ b/adapters/pubmatic/pubmatictest/supplemental/noAdSlot.json @@ -124,7 +124,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" }] }] } \ No newline at end of file diff --git a/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json b/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json index c58b1e6097..e3a5ccf19f 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json +++ b/adapters/pubmatic/pubmatictest/supplemental/pmZoneIDInKeywords.json @@ -155,7 +155,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json b/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json index abffb57ecb..cc1cc136a7 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json +++ b/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json @@ -163,7 +163,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json b/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json index 5d19a1f500..3d6887986b 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json +++ b/adapters/pubmatic/pubmatictest/supplemental/trimPublisherID.json @@ -153,7 +153,8 @@ "dspid": 6, "deal_channel": 1 } - } + }, + "type": "banner" } ] } From 2e68268ab6d65c00f5a93d906fd80f73eb31e8a9 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Tue, 8 Jul 2025 15:51:36 -0400 Subject: [PATCH 016/272] Fix: Remove module per request JSON marshal and add custom viper decoder (#4422) --- config/account.go | 15 +- config/account_module_decoder.go | 61 ++++++ config/account_module_decoder_test.go | 304 ++++++++++++++++++++++++++ config/config.go | 2 +- 4 files changed, 368 insertions(+), 14 deletions(-) create mode 100644 config/account_module_decoder.go create mode 100644 config/account_module_decoder_test.go diff --git a/config/account.go b/config/account.go index dd3d0d2071..c87ce5d1b1 100644 --- a/config/account.go +++ b/config/account.go @@ -320,7 +320,7 @@ type AccountHooks struct { // AccountModules mapping provides account-level module configuration // format: map[vendor_name]map[module_name]json.RawMessage -type AccountModules map[string]map[string]interface{} +type AccountModules map[string]map[string]json.RawMessage // ModuleConfig returns the account-level module config. // The id argument must be passed in the form "vendor.module_name", @@ -333,18 +333,7 @@ func (m AccountModules) ModuleConfig(id string) (json.RawMessage, error) { vendor := ns[0] module := ns[1] - - data, found := m[vendor][module] - if !found { - return nil, nil - } - - bytes, err := json.Marshal(data) - if err != nil { - return nil, fmt.Errorf("failed to marshal module config for %s: %w", id, err) - } - - return json.RawMessage(bytes), nil + return m[vendor][module], nil } type AccountPrivacy struct { diff --git a/config/account_module_decoder.go b/config/account_module_decoder.go new file mode 100644 index 0000000000..950460cc50 --- /dev/null +++ b/config/account_module_decoder.go @@ -0,0 +1,61 @@ +package config + +import ( + "encoding/json" + "fmt" + "reflect" + + "github.com/mitchellh/mapstructure" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +// AccountModulesHookFunc returns a mapstructure.DecodeHookFuncType that converts +// a map[string]interface{} to a map[string]map[string]json.RawMessage for the +// AccountModules type. This is used to handle the custom decoding of account modules +// in the configuration. +func AccountModulesHookFunc() mapstructure.DecodeHookFuncType { + return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + if f.Kind() != reflect.Map { + return data, nil + } + + if t != reflect.TypeOf(AccountModules{}) { + return data, nil + } + + result, err := convertToRawMessageMap(data.(map[string]interface{})) + if err != nil { + return nil, fmt.Errorf("failed to convert account modules map: %w", err) + } + return result, nil + } +} + +// convertToRawMessageMap converts a map[string]interface{} to a map[string]map[string]json.RawMessage. +// It marshals each inner value to json.RawMessage, allowing for flexible storage of arbitrary JSON structures. +func convertToRawMessageMap(input map[string]interface{}) (map[string]map[string]json.RawMessage, error) { + result := make(map[string]map[string]json.RawMessage, len(input)) + + for outerKey, outerValue := range input { + if outerValue == nil { + result[outerKey] = nil + continue + } + + innerMap, ok := outerValue.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("failed to convert inner map for %s", outerKey) + } + + resultInnerMap := make(map[string]json.RawMessage, len(innerMap)) + for innerKey, innerValue := range innerMap { + rawBytes, err := jsonutil.Marshal(innerValue) + if err != nil { + return nil, fmt.Errorf("failed to marshal value for %s.%s: %w", outerKey, innerKey, err) + } + resultInnerMap[innerKey] = rawBytes + } + result[outerKey] = resultInnerMap + } + return result, nil +} diff --git a/config/account_module_decoder_test.go b/config/account_module_decoder_test.go new file mode 100644 index 0000000000..fc3119f84a --- /dev/null +++ b/config/account_module_decoder_test.go @@ -0,0 +1,304 @@ +package config + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAccountModulesHookFunc(t *testing.T) { + // Create the hook function to test + hookFunc := AccountModulesHookFunc() + + // Define AccountModules type for reference + var accountModulesType = reflect.TypeOf(AccountModules{}) + + // Define some test types + type OtherType struct{} + var otherType = reflect.TypeOf(OtherType{}) + var mapStringInterface = reflect.TypeOf(map[string]interface{}{}) + var sliceType = reflect.TypeOf([]string{}) + + tests := []struct { + name string + fromType reflect.Type + toType reflect.Type + inputData interface{} + expectedData interface{} + expectSamePtr bool + expectError bool + errorContains string + }{ + { + name: "non-map-source-returns-same-data", + fromType: sliceType, + toType: accountModulesType, + inputData: []string{"test"}, + expectedData: []string{"test"}, + expectSamePtr: true, + expectError: false, + }, + { + name: "different-target-type-returns-same-data", + fromType: mapStringInterface, + toType: otherType, + inputData: map[string]interface{}{"key": "value"}, + expectedData: map[string]interface{}{"key": "value"}, + expectSamePtr: true, + expectError: false, + }, + { + name: "empty-map-converts-to-empty-account-modules", + fromType: mapStringInterface, + toType: accountModulesType, + inputData: map[string]interface{}{}, + expectedData: map[string]map[string]json.RawMessage{}, + expectError: false, + }, + { + name: "valid-input-successfully-converts", + fromType: mapStringInterface, + toType: accountModulesType, + inputData: map[string]interface{}{ + "vendor1": map[string]interface{}{ + "module1": true, + "module2": map[string]interface{}{ + "key": map[string]interface{}{ + "nestedKey": map[string]interface{}{ + "subKey": "subValue", + }, + }, + }, + }, + }, + expectedData: map[string]map[string]json.RawMessage{ + "vendor1": { + "module1": json.RawMessage(`true`), + "module2": json.RawMessage(`{"key":{"nestedKey":{"subKey":"subValue"}}}`), + }, + }, + expectError: false, + }, + { + name: "nil-vendor-config-handled-correctly", + fromType: mapStringInterface, + toType: accountModulesType, + inputData: map[string]interface{}{ + "vendor1": nil, + }, + expectedData: map[string]map[string]json.RawMessage{ + "vendor1": nil, + }, + expectError: false, + }, + { + name: "invalid-inner-map-returns-error", + fromType: mapStringInterface, + toType: accountModulesType, + inputData: map[string]interface{}{ + "vendor1": "not-a-map", + }, + expectError: true, + errorContains: "failed to convert inner map for vendor1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := hookFunc(tt.fromType, tt.toType, tt.inputData) + + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorContains) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + + if tt.expectSamePtr { + // When the input should be returned unchanged + assert.Equal(t, tt.inputData, result) + } else { + // For converted data, compare structures + expectedVendors, ok := tt.expectedData.(map[string]map[string]json.RawMessage) + assert.True(t, ok, "Expected data should be map[string]map[string]json.RawMessage") + + resultVendors, ok := result.(map[string]map[string]json.RawMessage) + assert.True(t, ok, "Result should be map[string]map[string]json.RawMessage") + + // Verify maps have same key count + assert.Len(t, resultVendors, len(expectedVendors)) + + // Compare each module's config + for vendorName, expectedModules := range expectedVendors { + actualModules, exists := resultVendors[vendorName] + assert.True(t, exists, "Expected vendor %s in result", vendorName) + + if expectedModules == nil { + assert.Nil(t, actualModules, "Expected nil modules for vendor %s", vendorName) + continue + } + + // Compare each config key + assert.Len(t, actualModules, len(expectedModules), + "Config for vendor %s should have %d modules", vendorName, len(expectedModules)) + + for moduleName, expectedConfig := range expectedModules { + actualConfig, exists := actualModules[moduleName] + assert.True(t, exists, "Expected module %s for vendor %s", moduleName, vendorName) + + // Compare JSON raw messages by converting to string + assert.JSONEq(t, string(expectedConfig), string(actualConfig), + "Value mismatch for vendor %s, module %s", vendorName, moduleName) + } + } + } + } + }) + } +} + +func TestConvertToRawMessageMap(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + expectedOutput map[string]map[string]json.RawMessage + expectError bool + errorContains string + }{ + { + name: "nil-input", + input: nil, + expectedOutput: map[string]map[string]json.RawMessage{}, + expectError: false, + }, + { + name: "empty-input", + input: map[string]interface{}{}, + expectedOutput: map[string]map[string]json.RawMessage{}, + expectError: false, + }, + { + name: "nil-vendor-config", + input: map[string]interface{}{ + "vendor1": nil, + }, + expectedOutput: map[string]map[string]json.RawMessage{ + "vendor1": nil, + }, + expectError: false, + }, + { + name: "nil-module-config", + input: map[string]interface{}{ + "vendor1": map[string]interface{}{ + "module1": nil, + }, + }, + expectedOutput: map[string]map[string]json.RawMessage{ + "vendor1": { + "module1": json.RawMessage(`null`), + }, + }, + expectError: false, + }, + { + name: "single-vendor-simple-module-values", + input: map[string]interface{}{ + "vendor1": map[string]interface{}{ + "module1": true, + "module2": 42, + "module3": "test-module", + }, + }, + expectedOutput: map[string]map[string]json.RawMessage{ + "vendor1": { + "module1": json.RawMessage(`true`), + "module2": json.RawMessage(`42`), + "module3": json.RawMessage(`"test-module"`), + }, + }, + expectError: false, + }, + { + name: "multiple-vendors-complex-module-values", + input: map[string]interface{}{ + "vendor1": map[string]interface{}{ + "module1": map[string]interface{}{ + "key": "value", + }, + "module2": map[string]interface{}{ + "key": map[string]interface{}{ + "nestedKey": map[string]interface{}{ + "subKey": "subValue", + }, + }, + }, + }, + "vendor2": map[string]interface{}{ + "module3": false, + "module4": []interface{}{1, 2, 3}, + }, + }, + expectedOutput: map[string]map[string]json.RawMessage{ + "vendor1": { + "module1": json.RawMessage(`{"key":"value"}`), + "module2": json.RawMessage(`{"key":{"nestedKey":{"subKey":"subValue"}}}`), + }, + "vendor2": { + "module3": json.RawMessage(`false`), + "module4": json.RawMessage(`[1,2,3]`), + }, + }, + expectError: false, + }, + { + name: "invalid-inner-map-type", + input: map[string]interface{}{ + "vendor1": "not-a-map", + }, + expectError: true, + errorContains: "failed to convert inner map for vendor1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := convertToRawMessageMap(tt.input) + + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorContains) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + + assert.Equal(t, len(tt.expectedOutput), len(result), "Output maps should have the same number of keys") + + // Compare each vendor's config + for vendor, expectedModules := range tt.expectedOutput { + modules, exists := result[vendor] + assert.True(t, exists, "Expected vendor %s in result", vendor) + + if expectedModules == nil { + assert.Nil(t, modules, "Expected nil config for vendor %s", vendor) + continue + } + + // Compare each module key + assert.Len(t, modules, len(expectedModules), + "Config for vendor %s should have %d modules", vendor, len(expectedModules)) + + for module, expectedConfig := range expectedModules { + actualConfig, exists := modules[module] + assert.True(t, exists, "Expected config key %s for module %s", module, vendor) + + assert.JSONEq(t, string(expectedConfig), string(actualConfig), + "Config mismatch for vendor %s, module %s", vendor, module) + } + } + } + }) + } +} diff --git a/config/config.go b/config/config.go index 9434eab5ef..3a2e05179e 100644 --- a/config/config.go +++ b/config/config.go @@ -716,7 +716,7 @@ func (cfg *TimeoutNotification) validate(errs []error) []error { // New uses viper to get our server configurations. func New(v *viper.Viper, bidderInfos BidderInfos, normalizeBidderName openrtb_ext.BidderNameNormalizer) (*Configuration, error) { var c Configuration - if err := v.Unmarshal(&c); err != nil { + if err := v.Unmarshal(&c, viper.DecodeHook(AccountModulesHookFunc())); err != nil { return nil, fmt.Errorf("viper failed to unmarshal app config: %v", err) } From 4c48b396a295908bb1b35d462efc4de719fdad7b Mon Sep 17 00:00:00 2001 From: Rich Audience Date: Tue, 8 Jul 2025 21:52:56 +0200 Subject: [PATCH 017/272] RichAudience: change endpoint to https (#4384) Co-authored-by: IAN --- adapters/richaudience/richaudience_test.go | 4 ++-- .../richaudiencetest/exemplary/single-banner-app.json | 8 ++++---- .../exemplary/single-banner-defaultCurrency.json | 4 ++-- .../exemplary/single-banner-deviceConfig.json | 8 ++++---- .../richaudiencetest/exemplary/single-banner-extUser.json | 4 ++-- .../exemplary/single-banner-floorPrice.json | 8 ++++---- .../richaudiencetest/exemplary/single-banner-iPv6.json | 4 ++-- .../exemplary/single-banner-nil-device.json | 4 ++-- .../exemplary/single-banner-nosecure.json | 8 ++++---- .../exemplary/single-banner-setCurrency.json | 8 ++++---- .../exemplary/single-banner-sitePage.json | 8 ++++---- .../richaudiencetest/exemplary/single-banner.json | 8 ++++---- .../richaudiencetest/exemplary/single-video.json | 8 ++++---- .../richaudiencetest/supplemental/bidTypeNotAssigned.json | 8 ++++---- .../richaudiencetest/supplemental/responseBlank.json | 6 +++--- .../richaudiencetest/supplemental/statusCode400.json | 6 +++--- .../richaudiencetest/supplemental/statusCodeError.json | 6 +++--- .../supplemental/unexpectedStatusCode.json | 4 ++-- static/bidder-info/richaudience.yaml | 2 +- 19 files changed, 58 insertions(+), 58 deletions(-) diff --git a/adapters/richaudience/richaudience_test.go b/adapters/richaudience/richaudience_test.go index fde825ef6a..342301f808 100644 --- a/adapters/richaudience/richaudience_test.go +++ b/adapters/richaudience/richaudience_test.go @@ -46,7 +46,7 @@ type richaudienceSite struct { func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderRichaudience, config.Adapter{ - Endpoint: "http://ortb.richaudience.com/ortb/?bidder=pbs", + Endpoint: "https://ortb.richaudience.com/ortb/?bidder=pbs", }, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { @@ -58,7 +58,7 @@ func TestJsonSamples(t *testing.T) { func TestGetBuilder(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderRichaudience, config.Adapter{ - Endpoint: "http://ortb.richaudience.com/ortb/?bidder=pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "https://ortb.richaudience.com/ortb/?bidder=pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Errorf("error %s", buildErr) diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json index a39101bd6e..ad0a10e469 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json @@ -49,11 +49,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -135,7 +135,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -156,4 +156,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json index 6a27630918..2c630bcb9c 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json @@ -40,7 +40,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": [ "application/json;charset=utf-8" @@ -143,4 +143,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json index c024fed6ff..2928927f48 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json @@ -37,11 +37,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -111,7 +111,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -132,4 +132,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json index 742d353fa7..6325affd1e 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json @@ -57,7 +57,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": [ "application/json;charset=utf-8" @@ -177,4 +177,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json index 8c5f8c0759..bc00032bf3 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json @@ -36,11 +36,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -110,7 +110,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -131,4 +131,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json index c16e639f00..e7a56d839b 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json @@ -41,7 +41,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": [ "application/json;charset=utf-8" @@ -145,4 +145,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json index 63f50c2d3e..8ad28053a1 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json @@ -50,7 +50,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": [ "application/json;charset=utf-8" @@ -166,4 +166,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json index bc0c7f5e51..3f14239c5b 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -108,7 +108,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -129,4 +129,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json index 17746300f7..d87f7f68c8 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -109,7 +109,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "EUR", @@ -130,4 +130,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json index 249113cf03..a45cb63eb1 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -108,7 +108,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -129,4 +129,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner.json index 249113cf03..a45cb63eb1 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -108,7 +108,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -129,4 +129,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-video.json b/adapters/richaudience/richaudiencetest/exemplary/single-video.json index fc158b43d0..390b7837d7 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-video.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-video.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -108,7 +108,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -129,4 +129,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json b/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json index 3e9723feba..6892ab8ad0 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json +++ b/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json @@ -36,11 +36,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "headers": { "Content-Type": ["application/json;charset=utf-8"], "Accept": ["application/json"], @@ -109,7 +109,7 @@ } } ], - + "expectedBidResponses": [ { "currency": "USD", @@ -130,4 +130,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/supplemental/responseBlank.json b/adapters/richaudience/richaudiencetest/supplemental/responseBlank.json index 89ee6a422d..d337db6851 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/responseBlank.json +++ b/adapters/richaudience/richaudiencetest/supplemental/responseBlank.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "body": { "id": "4d3f84eb-787b-42fb-a0cf-062690dadce3", "imp": [ @@ -90,4 +90,4 @@ } } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/supplemental/statusCode400.json b/adapters/richaudience/richaudiencetest/supplemental/statusCode400.json index 39e331a20b..84d6c124e6 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/statusCode400.json +++ b/adapters/richaudience/richaudiencetest/supplemental/statusCode400.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "body": { "id": "4d3f84eb-787b-42fb-a0cf-062690dadce3", "imp": [ @@ -93,4 +93,4 @@ "comparison": "literal" } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/supplemental/statusCodeError.json b/adapters/richaudience/richaudiencetest/supplemental/statusCodeError.json index 3b11abfe30..e1b7fbfc35 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/statusCodeError.json +++ b/adapters/richaudience/richaudiencetest/supplemental/statusCodeError.json @@ -35,11 +35,11 @@ "ext": {} } }, - + "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "body": { "id": "4d3f84eb-787b-42fb-a0cf-062690dadce3", "imp": [ @@ -93,4 +93,4 @@ "comparison": "literal" } ] - } \ No newline at end of file + } diff --git a/adapters/richaudience/richaudiencetest/supplemental/unexpectedStatusCode.json b/adapters/richaudience/richaudiencetest/supplemental/unexpectedStatusCode.json index 82a241bbea..55a89dfb39 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/unexpectedStatusCode.json +++ b/adapters/richaudience/richaudiencetest/supplemental/unexpectedStatusCode.json @@ -40,7 +40,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ortb.richaudience.com/ortb/?bidder=pbs", + "uri": "https://ortb.richaudience.com/ortb/?bidder=pbs", "body": { "id": "4d3f84eb-787b-42fb-a0cf-062690dadce3", "imp": [ @@ -94,4 +94,4 @@ "comparison": "literal" } ] -} \ No newline at end of file +} diff --git a/static/bidder-info/richaudience.yaml b/static/bidder-info/richaudience.yaml index d2f7abadeb..32e503878b 100644 --- a/static/bidder-info/richaudience.yaml +++ b/static/bidder-info/richaudience.yaml @@ -1,4 +1,4 @@ -endpoint: "http://ortb.richaudience.com/ortb/?bidder=pbs" +endpoint: "https://ortb.richaudience.com/ortb/?bidder=pbs" maintainer: email: partnerintegrations@richaudience.com gvlVendorID: 108 From a68a8e884de1986f3ae76c827d3641c6e94166da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Ney?= Date: Mon, 14 Jul 2025 20:33:54 +0200 Subject: [PATCH 018/272] Missena: Pass full openrtb request (#4394) --- adapters/missena/missena.go | 78 ++----- .../exemplary/bid-floor-currency.json | 197 ++++++++++-------- .../missenatest/exemplary/multiple-imps.json | 68 +++++- .../exemplary/simple-banner-ipv6.json | 44 +++- .../missenatest/exemplary/simple-banner.json | 43 +++- .../exemplary/valid-imp-error-imp.json | 68 +++++- .../missenatest/supplemental/status-204.json | 44 +++- .../missenatest/supplemental/status-400.json | 43 +++- .../supplemental/status-not-200.json | 44 +++- 9 files changed, 460 insertions(+), 169 deletions(-) diff --git a/adapters/missena/missena.go b/adapters/missena/missena.go index 1519cb4180..401f11d159 100644 --- a/adapters/missena/missena.go +++ b/adapters/missena/missena.go @@ -21,25 +21,18 @@ type adapter struct { } type MissenaAdRequest struct { - Adunit string `json:"adunit,omitempty"` - BuyerUID string `json:"buyeruid,omitempty"` - COPPA int8 `json:"coppa,omitempty"` - Currency string `json:"currency,omitempty"` - EIDs []openrtb2.EID `json:"userEids,omitempty"` - Floor float64 `json:"floor,omitempty"` - FloorCurrency string `json:"floor_currency,omitempty"` - GDPR bool `json:"consent_required,omitempty"` - GDPRConsent string `json:"consent_string,omitempty"` - IdempotencyKey string `json:"ik,omitempty"` - Referer string `json:"referer,omitempty"` - RefererCanonical string `json:"referer_canonical,omitempty"` - RequestID string `json:"request_id,omitempty"` - SChain *openrtb2.SupplyChain `json:"schain,omitempty"` - Timeout int64 `json:"timeout,omitempty"` - URL string `json:"url,omitempty"` - UserParams UserParams `json:"params"` - USPrivacy string `json:"us_privacy,omitempty"` - Version string `json:"version,omitempty"` + Adunit string `json:"adunit,omitempty"` + BuyerUID string `json:"buyeruid,omitempty"` + Currency string `json:"currency,omitempty"` + EIDs []openrtb2.EID `json:"userEids,omitempty"` + Floor float64 `json:"floor,omitempty"` + FloorCurrency string `json:"floor_currency,omitempty"` + IdempotencyKey string `json:"ik,omitempty"` + RequestID string `json:"request_id,omitempty"` + Timeout int64 `json:"timeout,omitempty"` + UserParams UserParams `json:"params"` + ORTB2 *openrtb2.BidRequest `json:"ortb2"` + Version string `json:"version,omitempty"` } type BidServerResponse struct { @@ -121,46 +114,15 @@ func (a *adapter) makeRequest(imp openrtb2.Imp, request *openrtb2.BidRequest, re } } - var schain *openrtb2.SupplyChain - if request.Source != nil { - schain = request.Source.SChain - } - - var buyerUID string - var eids []openrtb2.EID - var coppa int8 - var referer, refererCanonical string - - if request.User != nil { - buyerUID = request.User.BuyerUID - eids = request.User.EIDs - } - - if request.Regs != nil { - coppa = request.Regs.COPPA - } - - if request.Site != nil { - referer = request.Site.Page - refererCanonical = request.Site.Domain - } - missenaRequest := MissenaAdRequest{ - Adunit: imp.ID, - BuyerUID: buyerUID, - COPPA: coppa, - Currency: cur, - EIDs: eids, - Floor: floor, - FloorCurrency: floorCur, - GDPR: gdprApplies, - GDPRConsent: consentString, - IdempotencyKey: request.ID, - Referer: referer, - RefererCanonical: refererCanonical, - RequestID: request.ID, - SChain: schain, - Timeout: request.TMax, + Adunit: imp.ID, + Currency: cur, + Floor: floor, + FloorCurrency: floorCur, + IdempotencyKey: request.ID, + ORTB2: request, + RequestID: request.ID, + Timeout: request.TMax, UserParams: UserParams{ Formats: params.Formats, Placement: params.Placement, diff --git a/adapters/missena/missenatest/exemplary/bid-floor-currency.json b/adapters/missena/missenatest/exemplary/bid-floor-currency.json index d7c610804b..940a2451d8 100644 --- a/adapters/missena/missenatest/exemplary/bid-floor-currency.json +++ b/adapters/missena/missenatest/exemplary/bid-floor-currency.json @@ -1,94 +1,125 @@ { - "mockBidRequest": { - "id": "test-request-id", - "tmax": 500, - "cur": ["EUR", "USD"], - "site": { - "page": "https://publisher.com/url", - "domain": "publisher.com" - }, - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123" + "mockBidRequest": { + "id": "test-request-id", + "tmax": 500, + "cur": ["EUR", "USD"], + "site": { + "page": "https://publisher.com/url", + "domain": "publisher.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123" + }, + "user": {}, + "regs": { + "coppa": 0 + }, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 1.5, + "bidfloorcur": "USD", + "banner": { + "w": 300, + "h": 250 }, - "user": {}, - "regs": { - "coppa": 0 + "ext": { + "bidder": { + "apiKey": "test-api-key", + "formats": ["banner"], + "placement": "sticky" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?t=test-api-key", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"], + "X-Forwarded-For": ["123.123.123.123"], + "Referer": ["https://publisher.com/url"], + "Origin": ["https://publisher.com"] }, - "imp": [ - { - "id": "test-imp-id", - "bidfloor": 1.5, - "bidfloorcur": "USD", + "body": { + "adunit": "test-imp-id", + "currency": "USD", + "floor": 1.5, + "floor_currency": "USD", + "ik": "test-request-id", + "ortb2": { + "cur": ["EUR", "USD"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { "banner": { - "w": 300, - "h": 250 + "h": 250, + "w": 300 }, + "bidfloor": 1.5, + "bidfloorcur": "USD", "ext": { - "bidder": { - "apiKey": "test-api-key", - "formats": ["banner"], - "placement": "sticky" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://example.com/?t=test-api-key", - "headers": { - "Content-Type": ["application/json;charset=utf-8"], - "Accept": ["application/json"], - "User-Agent": ["test-user-agent"], - "X-Forwarded-For": ["123.123.123.123"], - "Referer": ["https://publisher.com/url"], - "Origin": ["https://publisher.com"] - }, - "body": { - "adunit": "test-imp-id", - "currency": "USD", - "floor": 1.5, - "floor_currency": "USD", - "ik": "test-request-id", - "referer": "https://publisher.com/url", - "referer_canonical": "publisher.com", - "request_id": "test-request-id", - "timeout": 500, - "params": { - "formats": ["banner"], - "placement": "sticky" - } + "bidder": { + "apiKey": "test-api-key", + "formats": ["banner"], + "placement": "sticky" + } }, - "impIDs": ["test-imp-id"] + "id": "test-imp-id" + } + ], + "regs": {}, + "site": { + "domain": "publisher.com", + "page": "https://publisher.com/url" }, - "mockResponse": { - "status": 200, - "body": { - "ad": "
test ad
", - "cpm": 2.5, - "currency": "USD", - "requestId": "test-request-id" - } - } + "tmax": 500, + "user": {} + }, + "request_id": "test-request-id", + "timeout": 500, + "params": { + "formats": ["banner"], + "placement": "sticky" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "ad": "
test ad
", + "cpm": 2.5, + "currency": "USD", + "requestId": "test-request-id" } - ], - "expectedBidResponses": [ + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "test-request-id", - "impid": "test-imp-id", - "price": 2.5, - "adm": "
test ad
", - "crid": "test-request-id" - }, - "type": "banner" - } - ] + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "
test ad
", + "crid": "test-request-id" + }, + "type": "banner" } - ] -} \ No newline at end of file + ] + } + ] +} diff --git a/adapters/missena/missenatest/exemplary/multiple-imps.json b/adapters/missena/missenatest/exemplary/multiple-imps.json index 285cda2613..9f0ea74ce3 100644 --- a/adapters/missena/missenatest/exemplary/multiple-imps.json +++ b/adapters/missena/missenatest/exemplary/multiple-imps.json @@ -77,16 +77,76 @@ }, "body": { "adunit": "test-imp-id-1", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement-1", + "test": "1" + } + }, + "id": "test-imp-id-1" + }, + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement-2", + "test": "1" + } + }, + "id": "test-imp-id-2" + }, + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": "abc" + }, + "id": "test-imp-id-3" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement-1", "test": "1" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json b/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json index edd3197c45..ab279f26b7 100644 --- a/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json +++ b/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json @@ -53,16 +53,52 @@ }, "body": { "adunit": "test-imp-id", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement", + "test": "1" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement", "test": "1" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/exemplary/simple-banner.json b/adapters/missena/missenatest/exemplary/simple-banner.json index f995b4634a..e2368579b5 100644 --- a/adapters/missena/missenatest/exemplary/simple-banner.json +++ b/adapters/missena/missenatest/exemplary/simple-banner.json @@ -52,15 +52,50 @@ }, "body": { "adunit": "test-imp-id", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json b/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json index 285cda2613..9f0ea74ce3 100644 --- a/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json +++ b/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json @@ -77,16 +77,76 @@ }, "body": { "adunit": "test-imp-id-1", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement-1", + "test": "1" + } + }, + "id": "test-imp-id-1" + }, + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement-2", + "test": "1" + } + }, + "id": "test-imp-id-2" + }, + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": "abc" + }, + "id": "test-imp-id-3" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement-1", "test": "1" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/supplemental/status-204.json b/adapters/missena/missenatest/supplemental/status-204.json index 469abdf618..4cd1a24b8a 100644 --- a/adapters/missena/missenatest/supplemental/status-204.json +++ b/adapters/missena/missenatest/supplemental/status-204.json @@ -53,16 +53,52 @@ }, "body": { "adunit": "test-imp-id", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement", + "test": "1" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement", "test": "1" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/supplemental/status-400.json b/adapters/missena/missenatest/supplemental/status-400.json index b6fbda5924..616fa05cab 100644 --- a/adapters/missena/missenatest/supplemental/status-400.json +++ b/adapters/missena/missenatest/supplemental/status-400.json @@ -52,15 +52,50 @@ }, "body": { "adunit": "test-imp-id", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, diff --git a/adapters/missena/missenatest/supplemental/status-not-200.json b/adapters/missena/missenatest/supplemental/status-not-200.json index afa2a7f94b..3dc28ab762 100644 --- a/adapters/missena/missenatest/supplemental/status-not-200.json +++ b/adapters/missena/missenatest/supplemental/status-not-200.json @@ -53,16 +53,52 @@ }, "body": { "adunit": "test-imp-id", - "consent_required": true, - "consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA", "currency": "EUR", "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement", + "test": "1" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, "params": { "placement": "test-placement", "test": "1" }, - "referer": "https://example.com/page", - "referer_canonical": "example.com", "request_id": "test-request-id", "timeout": 500 }, From b7ba074dc84d4ca4c739ae0adf9bd3c87bb8fe21 Mon Sep 17 00:00:00 2001 From: rediads <123890182+rediads@users.noreply.github.com> Date: Tue, 15 Jul 2025 00:22:37 +0530 Subject: [PATCH 019/272] New Adapter: Rediads (#4233) --- adapters/rediads/params_test.go | 44 +++++ adapters/rediads/rediads.go | 165 ++++++++++++++++++ adapters/rediads/rediads_test.go | 21 +++ .../rediadstest/exemplary/app_audio.json | 121 +++++++++++++ .../rediadstest/exemplary/app_banner.json | 136 +++++++++++++++ .../exemplary/app_banner_has_publisher.json | 138 +++++++++++++++ .../rediadstest/exemplary/app_native.json | 119 +++++++++++++ .../rediadstest/exemplary/app_video.json | 130 ++++++++++++++ .../rediadstest/exemplary/site_audio.json | 123 +++++++++++++ .../rediadstest/exemplary/site_banner.json | 139 +++++++++++++++ .../exemplary/site_banner_with_endpoint.json | 140 +++++++++++++++ .../rediadstest/exemplary/site_native.json | 121 +++++++++++++ .../rediadstest/exemplary/site_video.json | 132 ++++++++++++++ .../rediadstest/supplemental/bad_imp_ext.json | 90 ++++++++++ .../supplemental/bad_imp_ext_bidder.json | 92 ++++++++++ .../supplemental/bad_media_type.json | 81 +++++++++ .../supplemental/bad_response.json | 84 +++++++++ .../rediadstest/supplemental/status-204.json | 79 +++++++++ .../supplemental/status-not-200.json | 84 +++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_rediads.go | 7 + static/bidder-info/rediads.yaml | 26 +++ static/bidder-params/rediads.json | 18 ++ 24 files changed, 2094 insertions(+) create mode 100644 adapters/rediads/params_test.go create mode 100644 adapters/rediads/rediads.go create mode 100644 adapters/rediads/rediads_test.go create mode 100644 adapters/rediads/rediadstest/exemplary/app_audio.json create mode 100644 adapters/rediads/rediadstest/exemplary/app_banner.json create mode 100644 adapters/rediads/rediadstest/exemplary/app_banner_has_publisher.json create mode 100644 adapters/rediads/rediadstest/exemplary/app_native.json create mode 100644 adapters/rediads/rediadstest/exemplary/app_video.json create mode 100644 adapters/rediads/rediadstest/exemplary/site_audio.json create mode 100644 adapters/rediads/rediadstest/exemplary/site_banner.json create mode 100644 adapters/rediads/rediadstest/exemplary/site_banner_with_endpoint.json create mode 100644 adapters/rediads/rediadstest/exemplary/site_native.json create mode 100644 adapters/rediads/rediadstest/exemplary/site_video.json create mode 100644 adapters/rediads/rediadstest/supplemental/bad_imp_ext.json create mode 100644 adapters/rediads/rediadstest/supplemental/bad_imp_ext_bidder.json create mode 100644 adapters/rediads/rediadstest/supplemental/bad_media_type.json create mode 100644 adapters/rediads/rediadstest/supplemental/bad_response.json create mode 100644 adapters/rediads/rediadstest/supplemental/status-204.json create mode 100644 adapters/rediads/rediadstest/supplemental/status-not-200.json create mode 100644 openrtb_ext/imp_rediads.go create mode 100644 static/bidder-info/rediads.yaml create mode 100644 static/bidder-params/rediads.json diff --git a/adapters/rediads/params_test.go b/adapters/rediads/params_test.go new file mode 100644 index 0000000000..af69698237 --- /dev/null +++ b/adapters/rediads/params_test.go @@ -0,0 +1,44 @@ +package rediads + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderRediads, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderRediads, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"account_id": "123"}`, + `{"account_id": "123", "slot": "12345"}`, + `{"account_id": "123", "slot": "12345", "endpoint": "https://bidding.rediads.com/openrtb2/auction"}`, +} + +var invalidParams = []string{ + `{"account": 42}`, `{}`, +} diff --git a/adapters/rediads/rediads.go b/adapters/rediads/rediads.go new file mode 100644 index 0000000000..cfa60eacf6 --- /dev/null +++ b/adapters/rediads/rediads.go @@ -0,0 +1,165 @@ +package rediads + +import ( + "fmt" + "net/url" + "strings" + + "github.com/buger/jsonparser" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the adapter for the given bidder with the given config. +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, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errors []error + var accountID string + var endpoint string + + // Iterate through all impressions in the request + for i, imp := range request.Imp { + // Extract and validate bidder-specific params from imp.Ext + var bidderExt adapters.ExtImpBidder + var rediadsExt openrtb_ext.ExtImpRediads + + // Unmarshal bidder extension + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + errors = append(errors, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid Ext format in impression %s", imp.ID), + }) + continue + } + // Remove "prebid" and "bidder" from imp.Ext + newExt := jsonparser.Delete(imp.Ext, "prebid") + newExt = jsonparser.Delete(newExt, "bidder") + imp.Ext = newExt + + // Unmarshal custom bidder params + if err := jsonutil.Unmarshal(bidderExt.Bidder, &rediadsExt); err != nil { + errors = append(errors, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid bidder params in impression %s", imp.ID), + }) + continue + } + + // Set accountID and slot to use in publisher id and imp tag id respectively + accountID = rediadsExt.AccountID + endpoint = rediadsExt.Endpoint + + // Set tagid in the imp object + if rediadsExt.Slot != "" { + imp.TagID = rediadsExt.Slot + } + request.Imp[i] = imp + } + + // Update site or app publisher ID with accountID + if request.Site != nil { + siteCopy := *request.Site + if siteCopy.Publisher != nil { + publisherCopy := *siteCopy.Publisher + publisherCopy.ID = accountID + siteCopy.Publisher = &publisherCopy + } else { + siteCopy.Publisher = &openrtb2.Publisher{ID: accountID} + } + request.Site = &siteCopy + } else if request.App != nil { + appCopy := *request.App + if appCopy.Publisher != nil { + publisherCopy := *appCopy.Publisher + publisherCopy.ID = accountID + appCopy.Publisher = &publisherCopy + } else { + appCopy.Publisher = &openrtb2.Publisher{ID: accountID} + } + request.App = &appCopy + } + + // Marshal the final request + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{err} + } + + finalEndpoint := a.endpoint + if endpoint != "" { + parsedURL, _ := url.Parse(finalEndpoint) + host := parsedURL.Host + parts := strings.Split(host, ".") + parts[0] = endpoint + newHost := strings.Join(parts, ".") + finalEndpoint = strings.Replace(finalEndpoint, host, newHost, 1) + } + + // Build adapters.RequestData + requestData := &adapters.RequestData{ + Method: "POST", + Uri: finalEndpoint, + Body: requestJSON, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, errors +} + +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.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) + } +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + bidType, err := getMediaTypeForBid(bid) + if err != nil { + return nil, []error{err} + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + return bidResponse, nil +} diff --git a/adapters/rediads/rediads_test.go b/adapters/rediads/rediads_test.go new file mode 100644 index 0000000000..b5e935b680 --- /dev/null +++ b/adapters/rediads/rediads_test.go @@ -0,0 +1,21 @@ +package rediads + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderRediads, config.Adapter{ + Endpoint: "https://fake.test.io/pserver"}, + config.Server{ExternalUrl: "http://hosturl.com"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "rediadstest", bidder) +} diff --git a/adapters/rediads/rediadstest/exemplary/app_audio.json b/adapters/rediads/rediadstest/exemplary/app_audio.json new file mode 100644 index 0000000000..9f71c5cbea --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/app_audio.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "mtype": 3, + "ext": { + "bidder": { + "account_id": "569749" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": {} + } + ], + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "569749" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rediads", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "mtype": 3, + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "https://advertiser.example.com" + ], + "cid": "958", + "crid": "29681110" + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "mtype": 3, + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "https://advertiser.example.com" + ], + "cid": "958", + "crid": "29681110" + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/rediads/rediadstest/exemplary/app_banner.json b/adapters/rediads/rediadstest/exemplary/app_banner.json new file mode 100644 index 0000000000..a09f5dc37d --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/app_banner.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999", + "slot": "234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/app_banner_has_publisher.json b/adapters/rediads/rediadstest/exemplary/app_banner_has_publisher.json new file mode 100644 index 0000000000..19a674968d --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/app_banner_has_publisher.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "com.rediads.testrediadsapplication" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/app_native.json b/adapters/rediads/rediadstest/exemplary/app_native.json new file mode 100644 index 0000000000..df05a67033 --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/app_native.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/app_video.json b/adapters/rediads/rediadstest/exemplary/app_video.json new file mode 100644 index 0000000000..5a9132ab6b --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/app_video.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "account_id": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "test" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + } + } + ] + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/site_audio.json b/adapters/rediads/rediadstest/exemplary/site_audio.json new file mode 100644 index 0000000000..78edcae4f7 --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/site_audio.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com" + } + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "mtype": 3, + "ext": { + "bidder": { + "account_id": "569749" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": {} + } + ], + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "569749" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rediads", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "mtype": 3, + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "https://advertiser.example.com" + ], + "cid": "958", + "crid": "29681110" + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "mtype": 3, + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "https://advertiser.example.com" + ], + "cid": "958", + "crid": "29681110" + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/site_banner.json b/adapters/rediads/rediadstest/exemplary/site_banner.json new file mode 100644 index 0000000000..8c33ff0bbe --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/site_banner.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999", + "slot": "234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": {} + } + ], + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/site_banner_with_endpoint.json b/adapters/rediads/rediadstest/exemplary/site_banner_with_endpoint.json new file mode 100644 index 0000000000..aa0eb01283 --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/site_banner_with_endpoint.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999", + "slot": "234", + "endpoint": "bidding2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bidding2.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": {} + } + ], + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/site_native.json b/adapters/rediads/rediadstest/exemplary/site_native.json new file mode 100644 index 0000000000..e813c9934b --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/site_native.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + } + } + ], + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/exemplary/site_video.json b/adapters/rediads/rediadstest/exemplary/site_video.json new file mode 100644 index 0000000000..4bf718bcb2 --- /dev/null +++ b/adapters/rediads/rediadstest/exemplary/site_video.json @@ -0,0 +1,132 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "account_id": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "chrome" + }, + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "test" + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + } + } + ] + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rediads/rediadstest/supplemental/bad_imp_ext.json b/adapters/rediads/rediadstest/supplemental/bad_imp_ext.json new file mode 100644 index 0000000000..dbfb983e7c --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/bad_imp_ext.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": "" + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid bidder params in impression test-imp-id", + "comparison": "literal" + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/rediads/rediadstest/supplemental/bad_imp_ext_bidder.json b/adapters/rediads/rediadstest/supplemental/bad_imp_ext_bidder.json new file mode 100644 index 0000000000..b972721607 --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/bad_imp_ext_bidder.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": "{Invalid json}" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "234", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": "{Invalid json}" + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": "" + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid bidder params in impression test-imp-id", + "comparison": "literal" + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/rediads/rediadstest/supplemental/bad_media_type.json b/adapters/rediads/rediadstest/supplemental/bad_media_type.json new file mode 100644 index 0000000000..3c594f8bbd --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/bad_media_type.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "account_id": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext":{} + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "test" + } + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": {} + } + ], + "seat": "rediads" + } + ], + "cur": "USD" + } + } + }], + "expectedMakeBidsErrors": [ + { + "value": "could not define media type for impression: test-imp-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/rediads/rediadstest/supplemental/bad_response.json b/adapters/rediads/rediadstest/supplemental/bad_response.json new file mode 100644 index 0000000000..cceb26defa --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/bad_response.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + }], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/rediads/rediadstest/supplemental/status-204.json b/adapters/rediads/rediadstest/supplemental/status-204.json new file mode 100644 index 0000000000..cda60f8994 --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/status-204.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} diff --git a/adapters/rediads/rediadstest/supplemental/status-not-200.json b/adapters/rediads/rediadstest/supplemental/status-not-200.json new file mode 100644 index 0000000000..86b2a28926 --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/status-not-200.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "account_id": "999" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + } + } + ], + "app": { + "id": "1", + "bundle": "com.rediads.testrediadsapplication", + "publisher": { + "id": "999" + } + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 404, + "body": {} + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index ba0ff57d4a..554763c7f9 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -184,6 +184,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/pwbid" "github.com/prebid/prebid-server/v3/adapters/qt" "github.com/prebid/prebid-server/v3/adapters/readpeak" + "github.com/prebid/prebid-server/v3/adapters/rediads" "github.com/prebid/prebid-server/v3/adapters/relevantdigital" "github.com/prebid/prebid-server/v3/adapters/resetdigital" "github.com/prebid/prebid-server/v3/adapters/revcontent" @@ -443,6 +444,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderPWBid: pwbid.Builder, openrtb_ext.BidderQT: qt.Builder, openrtb_ext.BidderReadpeak: readpeak.Builder, + openrtb_ext.BidderRediads: rediads.Builder, openrtb_ext.BidderRelevantDigital: relevantdigital.Builder, openrtb_ext.BidderResetDigital: resetdigital.Builder, openrtb_ext.BidderRevcontent: revcontent.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index f43a63a85c..f5dd7e5561 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -202,6 +202,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderPWBid, BidderQT, BidderReadpeak, + BidderRediads, BidderRelevantDigital, BidderResetDigital, BidderRevcontent, @@ -565,6 +566,7 @@ const ( BidderPWBid BidderName = "pwbid" BidderQT BidderName = "qt" BidderReadpeak BidderName = "readpeak" + BidderRediads BidderName = "rediads" BidderRelevantDigital BidderName = "relevantdigital" BidderResetDigital BidderName = "resetdigital" BidderRevcontent BidderName = "revcontent" diff --git a/openrtb_ext/imp_rediads.go b/openrtb_ext/imp_rediads.go new file mode 100644 index 0000000000..a0971a8f7d --- /dev/null +++ b/openrtb_ext/imp_rediads.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpRediads struct { + AccountID string `json:"account_id"` + Slot string `json:"slot"` + Endpoint string `json:"endpoint"` +} diff --git a/static/bidder-info/rediads.yaml b/static/bidder-info/rediads.yaml new file mode 100644 index 0000000000..91f2a90835 --- /dev/null +++ b/static/bidder-info/rediads.yaml @@ -0,0 +1,26 @@ +endpoint: "https://bidding.rediads.com/openrtb2/auction" +geoscope: + - global +maintainer: + email: support@rediads.com +modifyingVastXmlAllowed: true +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - audio + - native + site: + mediaTypes: + - banner + - video + - audio + - native +userSync: + # rediads supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - iframe diff --git a/static/bidder-params/rediads.json b/static/bidder-params/rediads.json new file mode 100644 index 0000000000..85c9e545a2 --- /dev/null +++ b/static/bidder-params/rediads.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RediAds Adapter Params", + "description": "A schema which validates params accepted by the Rediads adapter", + "type": "object", + "properties": { + "account_id": { + "type": "string" + }, + "slot": { + "type": "string" + }, + "endpoint": { + "type": "string" + } + }, + "required": ["account_id"] +} From 4abff2686205ebbd1f320a6c779b1111b6ffdb56 Mon Sep 17 00:00:00 2001 From: abermanov-zeta <95416296+abermanov-zeta@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:06:08 +0200 Subject: [PATCH 020/272] Zeta Global SSP: Declare OpenRTB 2.6 and GPP support (#4389) --- static/bidder-info/zeta_global_ssp.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/static/bidder-info/zeta_global_ssp.yaml b/static/bidder-info/zeta_global_ssp.yaml index f4f50d94b7..9b06bc6839 100644 --- a/static/bidder-info/zeta_global_ssp.yaml +++ b/static/bidder-info/zeta_global_ssp.yaml @@ -20,6 +20,9 @@ capabilities: - audio userSync: redirect: - url: https://ssp.disqus.com/redirectuser?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}} + url: https://ssp.disqus.com/redirectuser?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}} userMacro: 'BUYERUID' +openrtb: + version: 2.6 + gpp-supported: true From 166ad0e642975a7c917fac54da5c158e54785c14 Mon Sep 17 00:00:00 2001 From: linux019 Date: Mon, 14 Jul 2025 22:19:38 +0300 Subject: [PATCH 021/272] Record metric unsuccessful for PBC non-200 response status code or error (#4341) Co-authored-by: oleksandr --- prebid_cache_client/client.go | 5 +++-- prebid_cache_client/client_test.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/prebid_cache_client/client.go b/prebid_cache_client/client.go index a409b4f7d1..c0a7ff83eb 100644 --- a/prebid_cache_client/client.go +++ b/prebid_cache_client/client.go @@ -116,13 +116,14 @@ func (c *clientImpl) PutJson(ctx context.Context, values []Cacheable) (uuids []s return uuidsToReturn, errs } defer anResp.Body.Close() - c.metrics.RecordPrebidCacheRequestTime(true, elapsedTime) responseBody, err := io.ReadAll(anResp.Body) - if anResp.StatusCode != 200 { + if anResp.StatusCode != 200 || err != nil { + c.metrics.RecordPrebidCacheRequestTime(false, elapsedTime) logError(&errs, "Prebid Cache call to %s returned %d: %s", c.putUrl, anResp.StatusCode, responseBody) return uuidsToReturn, errs } + c.metrics.RecordPrebidCacheRequestTime(true, elapsedTime) currentIndex := 0 processResponse := func(uuidObj []byte, _ jsonparser.ValueType, _ int, err error) { diff --git a/prebid_cache_client/client_test.go b/prebid_cache_client/client_test.go index f00a835a4a..31fc05d30b 100644 --- a/prebid_cache_client/client_test.go +++ b/prebid_cache_client/client_test.go @@ -49,7 +49,7 @@ func TestBadResponse(t *testing.T) { defer server.Close() metricsMock := &metrics.MetricsEngineMock{} - metricsMock.On("RecordPrebidCacheRequestTime", true, mock.Anything).Once() + metricsMock.On("RecordPrebidCacheRequestTime", false, mock.Anything).Once() client := &clientImpl{ httpClient: server.Client(), From cc01c7c9e06df27aec0fa3b23f7359ca4b4ad35b Mon Sep 17 00:00:00 2001 From: Roger <104763658+rogerDyl@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:48:42 +0200 Subject: [PATCH 022/272] New Adapter: Akcelo (#4237) --- adapters/akcelo/akcelo.go | 187 ++++++++++++++++++ adapters/akcelo/akcelo_test.go | 20 ++ .../exemplary/banner-single-imp.json | 107 ++++++++++ .../exemplary/video-single-imp.json | 117 +++++++++++ .../dont-override-site-publisher.json | 113 +++++++++++ .../media-type-banner-from-mtype.json | 99 ++++++++++ .../media-type-native-from-mtype.json | 99 ++++++++++ .../media-type-unknown-from-mtype.json | 93 +++++++++ .../media-type-video-from-mtype.json | 99 ++++++++++ .../supplemental/no-bid-response-ext.json | 92 +++++++++ .../supplemental/no-media-type.json | 93 +++++++++ .../akcelotest/supplemental/no-valid-imp.json | 13 ++ .../status-internal-server-error.json | 70 +++++++ .../supplemental/status-no-content.json | 64 ++++++ adapters/akcelo/params_test.go | 42 ++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_akcelo.go | 9 + static/bidder-info/akcelo.yaml | 9 + static/bidder-params/akcelo.json | 21 ++ 20 files changed, 1351 insertions(+) create mode 100644 adapters/akcelo/akcelo.go create mode 100644 adapters/akcelo/akcelo_test.go create mode 100644 adapters/akcelo/akcelotest/exemplary/banner-single-imp.json create mode 100644 adapters/akcelo/akcelotest/exemplary/video-single-imp.json create mode 100644 adapters/akcelo/akcelotest/supplemental/dont-override-site-publisher.json create mode 100644 adapters/akcelo/akcelotest/supplemental/media-type-banner-from-mtype.json create mode 100644 adapters/akcelo/akcelotest/supplemental/media-type-native-from-mtype.json create mode 100644 adapters/akcelo/akcelotest/supplemental/media-type-unknown-from-mtype.json create mode 100644 adapters/akcelo/akcelotest/supplemental/media-type-video-from-mtype.json create mode 100644 adapters/akcelo/akcelotest/supplemental/no-bid-response-ext.json create mode 100644 adapters/akcelo/akcelotest/supplemental/no-media-type.json create mode 100644 adapters/akcelo/akcelotest/supplemental/no-valid-imp.json create mode 100644 adapters/akcelo/akcelotest/supplemental/status-internal-server-error.json create mode 100644 adapters/akcelo/akcelotest/supplemental/status-no-content.json create mode 100644 adapters/akcelo/params_test.go create mode 100644 openrtb_ext/imp_akcelo.go create mode 100644 static/bidder-info/akcelo.yaml create mode 100644 static/bidder-params/akcelo.json diff --git a/adapters/akcelo/akcelo.go b/adapters/akcelo/akcelo.go new file mode 100644 index 0000000000..4abb4c9ef9 --- /dev/null +++ b/adapters/akcelo/akcelo.go @@ -0,0 +1,187 @@ +package akcelo + +import ( + "encoding/json" + "fmt" + "github.com/buger/jsonparser" + "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" + "github.com/prebid/prebid-server/v3/util/ptrutil" + "net/http" + "net/url" +) + +type adapter struct { + uri *url.URL +} + +type extObj struct { + Akcelo json.RawMessage `json:"akcelo"` +} + +var noValidSiteIdError = &errortypes.BadInput{Message: "Cannot find valid siteId"} +var noValidImpError = &errortypes.BadInput{Message: "No valid Imp"} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + uri, err := url.Parse(config.Endpoint) + if err != nil { + return nil, err + } + bidder := &adapter{uri: uri} + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + requestData, errs := a.prepareBidRequest(request) + return requestData, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + var bidResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResponse); err != nil { + return nil, []error{err} + } + return extractBids(bidResponse) +} + +func (a *adapter) prepareBidRequest(bidRequest *openrtb2.BidRequest) ([]*adapters.RequestData, []error) { + if len(bidRequest.Imp) == 0 { + return nil, []error{noValidImpError} + } + + bidRequest = createSitePublisher(bidRequest) + requestData := make([]*adapters.RequestData, 0, 1) + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + var errs []error + for i := range bidRequest.Imp { + imp := &bidRequest.Imp[i] + err := a.prepareImp(imp) + if err != nil { + errs = append(errs, err) + continue + } + } + if err := configureParentAccount(bidRequest); err != nil { + return nil, []error{err} + } + + var resultBidRequest, err = jsonutil.Marshal(bidRequest) + if err != nil { + errs = append(errs, err) + } + + requestData = append(requestData, &adapters.RequestData{ + Method: "POST", + Uri: a.uri.String(), + Body: resultBidRequest, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(bidRequest.Imp), + }) + return requestData, errs +} + +func createSitePublisher(bidRequest *openrtb2.BidRequest) *openrtb2.BidRequest { + akceloRequest := *bidRequest + if akceloRequest.Site == nil { + akceloRequest.Site = &openrtb2.Site{} + } else { + akceloRequest.Site = ptrutil.Clone(akceloRequest.Site) + } + if akceloRequest.Site.Publisher == nil { + akceloRequest.Site.Publisher = &openrtb2.Publisher{} + } else { + akceloRequest.Site.Publisher = ptrutil.Clone(akceloRequest.Site.Publisher) + } + return &akceloRequest +} + +func configureParentAccount(bidRequest *openrtb2.BidRequest) error { + if len(bidRequest.Imp) == 0 { + return noValidImpError + } + parentAccount, _, _, err := jsonparser.Get(bidRequest.Imp[0].Ext, "akcelo", "siteId") + if err != nil { + return noValidSiteIdError + } + var publisherExt = openrtb_ext.ExtPublisher{} + publisherExt.Prebid = &openrtb_ext.ExtPublisherPrebid{} + var parentAccountStr = string(parentAccount) + publisherExt.Prebid.ParentAccount = &parentAccountStr + bidRequest.Site.Publisher.Ext, err = jsonutil.Marshal(&publisherExt) + return err +} + +func (a *adapter) prepareImp(imp *openrtb2.Imp) error { + var extBidder adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &extBidder); err != nil { + return &errortypes.BadInput{Message: fmt.Sprintf("Unsupported imp : %s", imp.ID)} + } + + extJson, err := jsonutil.Marshal(extObj{Akcelo: extBidder.Bidder}) + if err != nil { + return &errortypes.BadInput{Message: fmt.Sprintf("Cannot set akcelo parameters : %s", imp.ID)} + } + imp.Ext = extJson + return nil +} + +func extractBids(bidResponse openrtb2.BidResponse) (*adapters.BidderResponse, []error) { + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(5) + var errs []error + for j := range bidResponse.SeatBid { + seat := bidResponse.SeatBid[j] + for i := range seat.Bid { + bid := seat.Bid[i] + bidType, err := getBidType(&bid) + if err != nil { + errs = append(errs, err) + continue + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + } + return bidderResponse, errs +} + +func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.MType != 0 { + 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 + default: + return "", fmt.Errorf("unable to get media type %d", bid.MType) + } + } + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + if err := jsonutil.Unmarshal(bid.Ext, &bidExt); err != nil { + return "", err + } + if bidExt.Prebid != nil { + return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) + } + } + return "", fmt.Errorf("missing media type for bid: %s", bid.ID) +} diff --git a/adapters/akcelo/akcelo_test.go b/adapters/akcelo/akcelo_test.go new file mode 100644 index 0000000000..a67a31efce --- /dev/null +++ b/adapters/akcelo/akcelo_test.go @@ -0,0 +1,20 @@ +package akcelo + +import ( + "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/stretchr/testify/require" + "testing" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderAJA, + config.Adapter{Endpoint: "https://localhost/bid/4"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}, + ) + + require.NoError(t, buildErr, "Builder returned unexpected error") + adapterstest.RunJSONBidderTest(t, "akcelotest", bidder) +} diff --git a/adapters/akcelo/akcelotest/exemplary/banner-single-imp.json b/adapters/akcelo/akcelotest/exemplary/banner-single-imp.json new file mode 100644 index 0000000000..b79ead477d --- /dev/null +++ b/adapters/akcelo/akcelotest/exemplary/banner-single-imp.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/exemplary/video-single-imp.json b/adapters/akcelo/akcelotest/exemplary/video-single-imp.json new file mode 100644 index 0000000000..e834f5514e --- /dev/null +++ b/adapters/akcelo/akcelotest/exemplary/video-single-imp.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "vast", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "vast", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/dont-override-site-publisher.json b/adapters/akcelo/akcelotest/supplemental/dont-override-site-publisher.json new file mode 100644 index 0000000000..8db476e59d --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/dont-override-site-publisher.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "name": "test-publisher" + } + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "name": "test-publisher", + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/media-type-banner-from-mtype.json b/adapters/akcelo/akcelotest/supplemental/media-type-banner-from-mtype.json new file mode 100644 index 0000000000..8b421bc674 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/media-type-banner-from-mtype.json @@ -0,0 +1,99 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 1 + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/media-type-native-from-mtype.json b/adapters/akcelo/akcelotest/supplemental/media-type-native-from-mtype.json new file mode 100644 index 0000000000..aa4135cf71 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/media-type-native-from-mtype.json @@ -0,0 +1,99 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 4 + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/media-type-unknown-from-mtype.json b/adapters/akcelo/akcelotest/supplemental/media-type-unknown-from-mtype.json new file mode 100644 index 0000000000..ebfbcfa530 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/media-type-unknown-from-mtype.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 6 + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unable to get media type 6", + "comparison": "literal" + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/media-type-video-from-mtype.json b/adapters/akcelo/akcelotest/supplemental/media-type-video-from-mtype.json new file mode 100644 index 0000000000..0a586def44 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/media-type-video-from-mtype.json @@ -0,0 +1,99 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 2 + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/no-bid-response-ext.json b/adapters/akcelo/akcelotest/supplemental/no-bid-response-ext.json new file mode 100644 index 0000000000..db065f2b13 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/no-bid-response-ext.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id" + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "missing media type for bid: test-bid-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/no-media-type.json b/adapters/akcelo/akcelotest/supplemental/no-media-type.json new file mode 100644 index 0000000000..4a5ae22c69 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/no-media-type.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1, + "adm": "
test
", + "crid": "test-creative-id", + "ext": {} + } + ] + } + ], + "bidid": "test-seatbid-id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "missing media type for bid: test-bid-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/no-valid-imp.json b/adapters/akcelo/akcelotest/supplemental/no-valid-imp.json new file mode 100644 index 0000000000..bdf4593b3f --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/no-valid-imp.json @@ -0,0 +1,13 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [], + "tmax": 500 + }, + "expectedMakeRequestsErrors": [ + { + "value": "No valid Imp", + "comparison": "literal" + } + ] +} diff --git a/adapters/akcelo/akcelotest/supplemental/status-internal-server-error.json b/adapters/akcelo/akcelotest/supplemental/status-internal-server-error.json new file mode 100644 index 0000000000..ace49136c7 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/status-internal-server-error.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/akcelo/akcelotest/supplemental/status-no-content.json b/adapters/akcelo/akcelotest/supplemental/status-no-content.json new file mode 100644 index 0000000000..b114d89677 --- /dev/null +++ b/adapters/akcelo/akcelotest/supplemental/status-no-content.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://localhost/bid/4", + "body": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "akcelo": { + "adUnitId": 123, + "siteId": 456 + } + } + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "parentAccount": "456" + } + } + } + }, + "tmax": 500 + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/akcelo/params_test.go b/adapters/akcelo/params_test.go new file mode 100644 index 0000000000..0ff4d9e01f --- /dev/null +++ b/adapters/akcelo/params_test.go @@ -0,0 +1,42 @@ +package akcelo + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema. %v", err) + + for _, p := range validParams { + err := validator.Validate(openrtb_ext.BidderAkcelo, json.RawMessage(p)) + assert.NoError(t, err, "Schema rejected valid params: %s", p) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema. %v", err) + + for _, p := range invalidParams { + err := validator.Validate(openrtb_ext.BidderAkcelo, json.RawMessage(p)) + assert.Error(t, err, "Schema allowed invalid params: %s", p) + } +} + +var validParams = []string{ + `{"adUnitId": 123, "siteId": 456}`, + `{"adUnitId": 123, "siteId": 456, "test": 0}`, + `{"adUnitId": 123, "siteId": 456, "test": 1}`, +} + +var invalidParams = []string{ + `{"adUnitId": 123}`, + `{"siteId": 456}`, + `{"siteId": 456, "test": 1}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 554763c7f9..a1ae3b3479 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -38,6 +38,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/adyoulike" "github.com/prebid/prebid-server/v3/adapters/aidem" "github.com/prebid/prebid-server/v3/adapters/aja" + "github.com/prebid/prebid-server/v3/adapters/akcelo" "github.com/prebid/prebid-server/v3/adapters/algorix" "github.com/prebid/prebid-server/v3/adapters/alkimi" "github.com/prebid/prebid-server/v3/adapters/amx" @@ -295,6 +296,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdyoulike: adyoulike.Builder, openrtb_ext.BidderAidem: aidem.Builder, openrtb_ext.BidderAJA: aja.Builder, + openrtb_ext.BidderAkcelo: akcelo.Builder, openrtb_ext.BidderAlgorix: algorix.Builder, openrtb_ext.BidderAlkimi: alkimi.Builder, openrtb_ext.BidderAMX: amx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index f5dd7e5561..3f81bea025 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -54,6 +54,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdyoulike, BidderAidem, BidderAJA, + BidderAkcelo, BidderAlgorix, BidderAlkimi, BidderAMX, @@ -418,6 +419,7 @@ const ( BidderAdyoulike BidderName = "adyoulike" BidderAidem BidderName = "aidem" BidderAJA BidderName = "aja" + BidderAkcelo BidderName = "akcelo" BidderAlgorix BidderName = "algorix" BidderAlkimi BidderName = "alkimi" BidderAMX BidderName = "amx" diff --git a/openrtb_ext/imp_akcelo.go b/openrtb_ext/imp_akcelo.go new file mode 100644 index 0000000000..5c85f17c9e --- /dev/null +++ b/openrtb_ext/imp_akcelo.go @@ -0,0 +1,9 @@ +package openrtb_ext + +import "encoding/json" + +type ExtImpAkcelo struct { + AdUnitID json.Number `json:"adUnitId,omitempty"` + SiteID json.Number `json:"siteId,omitempty"` + Test json.Number `json:"test,omitempty"` +} diff --git a/static/bidder-info/akcelo.yaml b/static/bidder-info/akcelo.yaml new file mode 100644 index 0000000000..281d9e87e9 --- /dev/null +++ b/static/bidder-info/akcelo.yaml @@ -0,0 +1,9 @@ +endpoint: "https://s2s.sportslocalmedia.com/openrtb2/auction" +maintainer: + email: "tech@akcelo.io" +capabilities: + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/akcelo.json b/static/bidder-params/akcelo.json new file mode 100644 index 0000000000..3626f1c919 --- /dev/null +++ b/static/bidder-params/akcelo.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Akcelo Adapter Params", + "description": "A schema which validates params accepted by the Akcelo adapter", + "type": "object", + "properties": { + "adUnitID": { + "type": "number", + "description": "The identifier of the ad unit. Will be provided by your account manager." + }, + "siteId": { + "type": "number", + "description": "The identifier of the site. Will be provided by your account manager." + }, + "test": { + "type": "number", + "description": "Whether to display test creatives or not. Default is 0." + } + }, + "required": ["adUnitId", "siteId"] +} From 9a7b75aacb66bf38af4a2fc0e95dd511cfb628bd Mon Sep 17 00:00:00 2001 From: zentotem Date: Mon, 14 Jul 2025 23:04:40 +0300 Subject: [PATCH 023/272] New Adapter: Zentotem (#4053) --- adapters/zentotem/zentotem.go | 93 ++++++++ adapters/zentotem/zentotem_test.go | 71 ++++++ .../zentotemtest/exemplary/banner.json | 204 ++++++++++++++++++ .../zentotemtest/exemplary/native.json | 166 ++++++++++++++ .../zentotemtest/exemplary/video.json | 202 +++++++++++++++++ .../supplemental/bad_response.json | 154 +++++++++++++ .../zentotemtest/supplemental/status_204.json | 150 +++++++++++++ .../zentotemtest/supplemental/status_400.json | 118 ++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + static/bidder-info/zentotem.yaml | 16 ++ static/bidder-params/zentotem.json | 7 + 12 files changed, 1185 insertions(+) create mode 100644 adapters/zentotem/zentotem.go create mode 100644 adapters/zentotem/zentotem_test.go create mode 100644 adapters/zentotem/zentotemtest/exemplary/banner.json create mode 100644 adapters/zentotem/zentotemtest/exemplary/native.json create mode 100644 adapters/zentotem/zentotemtest/exemplary/video.json create mode 100644 adapters/zentotem/zentotemtest/supplemental/bad_response.json create mode 100644 adapters/zentotem/zentotemtest/supplemental/status_204.json create mode 100644 adapters/zentotem/zentotemtest/supplemental/status_400.json create mode 100644 static/bidder-info/zentotem.yaml create mode 100644 static/bidder-params/zentotem.json diff --git a/adapters/zentotem/zentotem.go b/adapters/zentotem/zentotem.go new file mode 100644 index 0000000000..65c067443e --- /dev/null +++ b/adapters/zentotem/zentotem.go @@ -0,0 +1,93 @@ +package zentotem + +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/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the Zentotem adapter for the given bidder with the given config. +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, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + requests := make([]*adapters.RequestData, 0, len(request.Imp)) + var errors []error + + requestCopy := *request + for _, imp := range request.Imp { + requestCopy.Imp = []openrtb2.Imp{imp} + + requestJSON, err := json.Marshal(request) + if err != nil { + errors = append(errors, err) + continue + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: requestJSON, + ImpIDs: []string{imp.ID}, + } + requests = append(requests, requestData) + } + return requests, errors +} + +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 + } + + return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + var response openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + var errors []error + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, err := getMediaTypeForBid(seatBid.Bid[i]) + if err != nil { + errors = append(errors, err) + continue + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + return bidResponse, errors +} diff --git a/adapters/zentotem/zentotem_test.go b/adapters/zentotem/zentotem_test.go new file mode 100644 index 0000000000..cf608c4a41 --- /dev/null +++ b/adapters/zentotem/zentotem_test.go @@ -0,0 +1,71 @@ +package zentotem + +import ( + "github.com/prebid/openrtb/v20/openrtb2" + "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/stretchr/testify/assert" + "testing" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderZentotem, config.Adapter{ + Endpoint: "http://localhost/bid?sspuid=prebid"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "zentotemtest", bidder) +} + +func TestGetMediaTypeForBid(t *testing.T) { + tests := []struct { + name string + bid openrtb2.Bid + wantType openrtb_ext.BidType + wantErr bool + }{ + { + name: "get_bid_native_type", + bid: openrtb2.Bid{ + MType: 4, + }, + wantType: openrtb_ext.BidTypeNative, + wantErr: false, + }, + { + name: "get_bid_banner_type", + bid: openrtb2.Bid{ + MType: 1, + }, + wantType: openrtb_ext.BidTypeBanner, + wantErr: false, + }, + { + name: "get_bid_video_type", + bid: openrtb2.Bid{ + MType: 2, + }, + wantType: openrtb_ext.BidTypeVideo, + wantErr: false, + }, + { + name: "fail", + wantType: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bType, err := getMediaTypeForBid(tt.bid) + if (err != nil) != tt.wantErr { + t.Errorf("getMediaTypeForBid error = %v, wantErr %v", err, tt.wantErr) + } + + assert.Equal(t, bType, tt.wantType) + }) + } +} diff --git a/adapters/zentotem/zentotemtest/exemplary/banner.json b/adapters/zentotem/zentotemtest/exemplary/banner.json new file mode 100644 index 0000000000..389f2e687e --- /dev/null +++ b/adapters/zentotem/zentotemtest/exemplary/banner.json @@ -0,0 +1,204 @@ +{ + "mockBidRequest": { + "id": "test-imp-id", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "w": 320, + "h": 50, + "api": [ + 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "test-imp-id", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "w": 320, + "h": 50, + "api": [ + 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "40", + "impid": "1", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "40", + "adomain": [ + "app.apple.com" + ], + "crid": "40", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "seat": "boldwin" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "40", + "impid": "1", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "40", + "adomain": [ + "app.apple.com" + ], + "crid": "40", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/zentotem/zentotemtest/exemplary/native.json b/adapters/zentotem/zentotemtest/exemplary/native.json new file mode 100644 index 0000000000..3d7f75cc68 --- /dev/null +++ b/adapters/zentotem/zentotemtest/exemplary/native.json @@ -0,0 +1,166 @@ +{ + "mockBidRequest": { + "id": "o37934lssd34fgd", + "cur": [ + "USD", + "RUB" + ], + "at": 2, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "tagid": "ierui234fdfdf", + "secure": 1, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"data\":{\"type\":12,\"len\":15}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627,\"mimes\":[\"image\/png\",\"image\/jpeg\",\"image\/gif\",\"text\/html\"]}},{\"id\":4,\"data\":{\"type\":2,\"len\":90}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + } + } + ], + "device": { + "w": 375, + "h": 667, + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/112.0.5615.46 Mobile/15E148 Safari/604.1", + "ip": "69.75.122.146", + "ifa": "460384F3-D3B0-47CA-8090-F120F270A8B7", + "language": "en", + "geo": { + "country": "USA", + "region": "CA", + "city": "Los Angeles" + } + }, + "site": { + "id": "9fu48u347ru34o", + "domain": "some-domain", + "page": "some-page", + "publisher": { + "id": "p-93dj34di3344" + }, + "cat": [ + "IAB12", + "IAB17-12" + ] + }, + "user": { + "id": "d92a55e6-3eda-44c4-a448-14830a4c6838", + "buyeruid": "213ba1a2425be71ec5080b1d64b8450c" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "o37934lssd34fgd", + "cur": [ + "USD", + "RUB" + ], + "at": 2, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "tagid": "ierui234fdfdf", + "secure": 1, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"data\":{\"type\":12,\"len\":15}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627,\"mimes\":[\"image\/png\",\"image\/jpeg\",\"image\/gif\",\"text\/html\"]}},{\"id\":4,\"data\":{\"type\":2,\"len\":90}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + } + } + ], + "device": { + "w": 375, + "h": 667, + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/112.0.5615.46 Mobile/15E148 Safari/604.1", + "ip": "69.75.122.146", + "ifa": "460384F3-D3B0-47CA-8090-F120F270A8B7", + "language": "en", + "geo": { + "country": "USA", + "region": "CA", + "city": "Los Angeles" + } + }, + "site": { + "id": "9fu48u347ru34o", + "domain": "some-domain", + "page": "some-page", + "publisher": { + "id": "p-93dj34di3344" + }, + "cat": [ + "IAB12", + "IAB17-12" + ] + }, + "user": { + "id": "d92a55e6-3eda-44c4-a448-14830a4c6838", + "buyeruid": "213ba1a2425be71ec5080b1d64b8450c" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "40", + "impid": "1", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "40", + "adomain": [ + "app.apple.com" + ], + "crid": "40", + "w": 320, + "h": 50, + "mtype": 4 + } + ], + "seat": "boldwin" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "40", + "impid": "1", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "40", + "adomain": [ + "app.apple.com" + ], + "crid": "40", + "w": 320, + "h": 50, + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/zentotem/zentotemtest/exemplary/video.json b/adapters/zentotem/zentotemtest/exemplary/video.json new file mode 100644 index 0000000000..810dc5ef6e --- /dev/null +++ b/adapters/zentotem/zentotemtest/exemplary/video.json @@ -0,0 +1,202 @@ +{ + "mockBidRequest": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3 + ], + "w": 640, + "h": 360, + "linearity": 1, + "skip": 1, + "sequence": 1, + "boxingallowed": 1, + "placement": 1 + }, + "tagid": "27208-0", + "bidfloor": 0.35, + "secure": 1 + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3 + ], + "w": 640, + "h": 360, + "linearity": 1, + "skip": 1, + "sequence": 1, + "boxingallowed": 1, + "placement": 1 + }, + "tagid": "27208-0", + "bidfloor": 0.35, + "secure": 1 + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "43", + "impid": "8f3ac58c-1e03-4264-8619-f79ddb137110", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "43", + "adomain": [ + "app.apple.com" + ], + "crid": "43", + "w": 1280, + "h": 720, + "mtype": 2 + } + ], + "seat": "boldwin" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43", + "impid": "8f3ac58c-1e03-4264-8619-f79ddb137110", + "price": 150, + "nurl": "some-test-nurl", + "burl": "some-test-burl", + "adm": "some-test-adm", + "adid": "43", + "adomain": [ + "app.apple.com" + ], + "crid": "43", + "w": 1280, + "h": 720, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/zentotem/zentotemtest/supplemental/bad_response.json b/adapters/zentotem/zentotemtest/supplemental/bad_response.json new file mode 100644 index 0000000000..f0b72aca67 --- /dev/null +++ b/adapters/zentotem/zentotemtest/supplemental/bad_response.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "api": [ + 4, 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "api": [ + 4, 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "{\"id\"data.lost" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/zentotem/zentotemtest/supplemental/status_204.json b/adapters/zentotem/zentotemtest/supplemental/status_204.json new file mode 100644 index 0000000000..7a5b115a95 --- /dev/null +++ b/adapters/zentotem/zentotemtest/supplemental/status_204.json @@ -0,0 +1,150 @@ +{ + "mockBidRequest": { + "id": "test-imp-id", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "api": [ + 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "test-imp-id", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 10, + "bidfloorcur": "RUB", + "tagid": "65f0c2a2feb788d7", + "displaymanager": "Fyber", + "displaymanagerver": "10.1.1", + "banner": { + "api": [ + 5 + ], + "mimes": [ + "application/javascript", + "text/html", + "text/javascript", + "image/png", + "image/jpeg", + "image/gif" + ] + } + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/zentotem/zentotemtest/supplemental/status_400.json b/adapters/zentotem/zentotemtest/supplemental/status_400.json new file mode 100644 index 0000000000..426ec2c3cd --- /dev/null +++ b/adapters/zentotem/zentotemtest/supplemental/status_400.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id" + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/bid?sspuid=prebid", + "body": { + "id": "058e84c8-3684-4725-be57-6a211fb8abc3", + "at": 2, + "bcat": [ "IAB8-18", "IAB8-5", "IAB9-9" ], + "cur": [ + "RUB" + ], + "tmax": 250, + "imp": [ + { + "id": "test-imp-id" + } + ], + "app": { + "privacypolicy": 1, + "paid": 0, + "id": "1757830", + "name": "some-app-name", + "bundle": "some-app-bundle", + "storeurl": "some-store-url", + "cat": [ + + "IAB1-1" + ], + "publisher": { + "id": "gambling" + } + }, + "device": { + "dnt": 0, + "devicetype": 4, + "h": 980, + "w": 350, + "connectiontype": 2, + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21 Build/HUAWEIYAL-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.131 Mobile Safari/537.36", + "ip": "95.104.196.182", + "make": "Huawei", + "model": "YAL-L21", + "os": "Android", + "osv": "10.0", + "ifa": "6cecfc3c-de97-4861-ba6c-41a9dc94b391", + "geo": { + "country": "RUS" + } + }, + "user": { + "id": "6cecfc3c-de97-4861-ba6c-41a9dc94b391" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index a1ae3b3479..efc8f51482 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -249,6 +249,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/yieldlab" "github.com/prebid/prebid-server/v3/adapters/yieldmo" "github.com/prebid/prebid-server/v3/adapters/yieldone" + "github.com/prebid/prebid-server/v3/adapters/zentotem" "github.com/prebid/prebid-server/v3/adapters/zeroclickfraud" "github.com/prebid/prebid-server/v3/adapters/zeta_global_ssp" "github.com/prebid/prebid-server/v3/adapters/zmaticoo" @@ -509,6 +510,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderYieldlab: yieldlab.Builder, openrtb_ext.BidderYieldmo: yieldmo.Builder, openrtb_ext.BidderYieldone: yieldone.Builder, + openrtb_ext.BidderZentotem: zentotem.Builder, openrtb_ext.BidderZeroClickFraud: zeroclickfraud.Builder, openrtb_ext.BidderZetaGlobalSsp: zeta_global_ssp.Builder, openrtb_ext.BidderZmaticoo: zmaticoo.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 3f81bea025..5eb322826c 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -267,6 +267,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderYieldlab, BidderYieldmo, BidderYieldone, + BidderZentotem, BidderZeroClickFraud, BidderZetaGlobalSsp, BidderZmaticoo, @@ -632,6 +633,7 @@ const ( BidderYieldlab BidderName = "yieldlab" BidderYieldmo BidderName = "yieldmo" BidderYieldone BidderName = "yieldone" + BidderZentotem BidderName = "zentotem" BidderZeroClickFraud BidderName = "zeroclickfraud" BidderZetaGlobalSsp BidderName = "zeta_global_ssp" BidderZmaticoo BidderName = "zmaticoo" diff --git a/static/bidder-info/zentotem.yaml b/static/bidder-info/zentotem.yaml new file mode 100644 index 0000000000..a5d30c1ac6 --- /dev/null +++ b/static/bidder-info/zentotem.yaml @@ -0,0 +1,16 @@ +endpoint: "https://rtb.zentotem.net/bid?sspuid=cqlnvfk00bhs0b6rci6g" +maintainer: + email: support@zentotem.net +endpointCompression: gzip +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/zentotem.json b/static/bidder-params/zentotem.json new file mode 100644 index 0000000000..7bb3c46093 --- /dev/null +++ b/static/bidder-params/zentotem.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Zentotem Adapter Params", + "description": "A schema which validates params accepted by the Zentotem adapter", + "type": "object", + "properties": {} +} \ No newline at end of file From 9de1ba22883e64863dedbfe1de7f60d938977c92 Mon Sep 17 00:00:00 2001 From: Pete Date: Wed, 16 Jul 2025 05:37:25 +0300 Subject: [PATCH 024/272] New Adapter: Exco (#4250) --- adapters/exco/exco.go | 165 ++++++++++++++++ adapters/exco/exco_test.go | 27 +++ .../exemplary/app-single-imp-banner.json | 115 ++++++++++++ .../exemplary/app-single-imp-video.json | 116 ++++++++++++ .../exemplary/multiple-impressions.json | 177 ++++++++++++++++++ .../exemplary/site-single-imp-banner.json | 117 ++++++++++++ .../exemplary/site-single-imp-video.json | 119 ++++++++++++ .../supplemental/204-bid-response.json | 74 ++++++++ .../supplemental/503-bid-response.json | 78 ++++++++ .../supplemental/invalid-imp-ext-format.json | 18 ++ .../supplemental/invalid-imp-ext.json | 20 ++ .../supplemental/invalid-response-body.json | 80 ++++++++ .../supplemental/mediaType_error.json | 112 +++++++++++ .../supplemental/missing-publisher-app.json | 106 +++++++++++ .../supplemental/missing-publisher-site.json | 106 +++++++++++ adapters/exco/params_test.go | 62 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_exco.go | 7 + static/bidder-info/exco.yaml | 18 ++ static/bidder-params/exco.json | 24 +++ 21 files changed, 1545 insertions(+) create mode 100644 adapters/exco/exco.go create mode 100644 adapters/exco/exco_test.go create mode 100644 adapters/exco/excotest/exemplary/app-single-imp-banner.json create mode 100644 adapters/exco/excotest/exemplary/app-single-imp-video.json create mode 100644 adapters/exco/excotest/exemplary/multiple-impressions.json create mode 100644 adapters/exco/excotest/exemplary/site-single-imp-banner.json create mode 100644 adapters/exco/excotest/exemplary/site-single-imp-video.json create mode 100644 adapters/exco/excotest/supplemental/204-bid-response.json create mode 100644 adapters/exco/excotest/supplemental/503-bid-response.json create mode 100644 adapters/exco/excotest/supplemental/invalid-imp-ext-format.json create mode 100644 adapters/exco/excotest/supplemental/invalid-imp-ext.json create mode 100644 adapters/exco/excotest/supplemental/invalid-response-body.json create mode 100644 adapters/exco/excotest/supplemental/mediaType_error.json create mode 100644 adapters/exco/excotest/supplemental/missing-publisher-app.json create mode 100644 adapters/exco/excotest/supplemental/missing-publisher-site.json create mode 100644 adapters/exco/params_test.go create mode 100644 openrtb_ext/imp_exco.go create mode 100644 static/bidder-info/exco.yaml create mode 100644 static/bidder-params/exco.json diff --git a/adapters/exco/exco.go b/adapters/exco/exco.go new file mode 100644 index 0000000000..dc79c6ec1e --- /dev/null +++ b/adapters/exco/exco.go @@ -0,0 +1,165 @@ +package exco + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +// Builder initializes the EXCO adapter with the given configuration. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +// MakeRequests creates HTTP requests to the EXCO endpoint based on the OpenRTB bid request. +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + + adjustedReq, err := adjustRequest(request) + if err != nil { + return nil, append(errs, err) + } + + payload, _ := jsonutil.Marshal(adjustedReq) + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + reqData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: payload, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{reqData}, errs +} + +// MakeBids processes the HTTP response from the EXCO endpoint and extracts bid information. +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResponse); err != nil { + return nil, []error{err} + } + + var errs []error + bidderResponse := adapters.NewBidderResponse() + for _, seatBid := range bidResponse.SeatBid { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errs = append(errs, err) + continue + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + + return bidderResponse, errs +} + +// getMediaTypeForBid determines the media type of a bid based on its MType. +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 + default: + return "", fmt.Errorf("unrecognized bid_ad_type in response from exco: %d", bid.MType) + } +} + +// adjustRequest modifies the OpenRTB bid request to include EXCO-specific parameters. +func adjustRequest(request *openrtb2.BidRequest) (*openrtb2.BidRequest, error) { + var publisherId string + + // Extracts the publisher ID and tag ID from the impression extension. + // Updates the impression's TagID with the extracted value. + for i := 0; i < len(request.Imp); i++ { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[i].Ext, &bidderExt); err != nil { + // Handles invalid impression extension by returning a BadInput error. + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Information: %s", i, err.Error()), + } + } + + var impExt openrtb_ext.ImpExtExco + if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + // Handles invalid bidder extension by returning a BadInput error. + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext.bidder for impression index %d. Error Information: %s", i, err.Error()), + } + } + + publisherId = impExt.PublisherId + request.Imp[i].TagID = impExt.TagId + } + + // Creates a deep copy of the App object to avoid modifying the original request. + if request.App != nil { + appCopy := *request.App + request.App = &appCopy + + if request.App.Publisher == nil { + // Initializes the Publisher object if it is nil. + request.App.Publisher = &openrtb2.Publisher{} + } else { + // Creates a deep copy of the Publisher object. + publisherCopy := *request.App.Publisher + request.App.Publisher = &publisherCopy + } + + // Sets the Publisher ID to the extracted publisher ID. + request.App.Publisher.ID = publisherId + } + + // Creates a deep copy of the Site object to avoid modifying the original request. + if request.Site != nil { + siteCopy := *request.Site + request.Site = &siteCopy + + if request.Site.Publisher == nil { + // Initializes the Publisher object if it is nil. + request.Site.Publisher = &openrtb2.Publisher{} + } else { + // Creates a deep copy of the Publisher object. + publisherCopy := *request.Site.Publisher + request.Site.Publisher = &publisherCopy + } + + // Sets the Publisher ID to the extracted publisher ID. + request.Site.Publisher.ID = publisherId + } + + return request, nil +} diff --git a/adapters/exco/exco_test.go b/adapters/exco/exco_test.go new file mode 100644 index 0000000000..77ab4afe88 --- /dev/null +++ b/adapters/exco/exco_test.go @@ -0,0 +1,27 @@ +package exco + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + adapterConfig := config.Adapter{ + Endpoint: "https://testjsonsample.com", + } + serverConfig := config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 1, + DataCenter: "2", + } + bidder, buildErr := Builder(openrtb_ext.BidderExco, adapterConfig, serverConfig) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "excotest", bidder) +} diff --git a/adapters/exco/excotest/exemplary/app-single-imp-banner.json b/adapters/exco/excotest/exemplary/app-single-imp-banner.json new file mode 100644 index 0000000000..6ca30878f7 --- /dev/null +++ b/adapters/exco/excotest/exemplary/app-single-imp-banner.json @@ -0,0 +1,115 @@ +{ + "mockBidRequest": { + "id": "app-single-imp-banner", + "app": { + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "app-single-imp-banner_imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "app-single-imp-banner", + "app": { + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "app-single-imp-banner_imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "tagid": "exco-banner-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["app-single-imp-banner_imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "app-single-imp-banner", + "seatbid": [ + { + "bid": [ + { + "id": "app-single-imp-banner", + "impid": "app-single-imp-banner_imp", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + } + ], + "seat": "exco" + } + ], + "bidid": "app-single-imp-banner", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "app-single-imp-banner", + "impid": "app-single-imp-banner_imp", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/exemplary/app-single-imp-video.json b/adapters/exco/excotest/exemplary/app-single-imp-video.json new file mode 100644 index 0000000000..9eb2fa393e --- /dev/null +++ b/adapters/exco/excotest/exemplary/app-single-imp-video.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "app-single-imp-video", + "app": { + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "app-single-imp-video_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "app-single-imp-video", + "app": { + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [{ + "id": "app-single-imp-video_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "tagid": "exco-video-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + }] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["app-single-imp-video_imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "app-single-imp-video", + "seatbid": [ + { + "bid": [ + { + "id": "app-single-imp-video_imp", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + } + ], + "seat": "exco" + } + ], + "bidid": "app-single-imp-video", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "app-single-imp-video_imp", + "impid": "", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/exemplary/multiple-impressions.json b/adapters/exco/excotest/exemplary/multiple-impressions.json new file mode 100644 index 0000000000..234dfa0429 --- /dev/null +++ b/adapters/exco/excotest/exemplary/multiple-impressions.json @@ -0,0 +1,177 @@ +{ + "mockBidRequest": { + "id": "multiple-impressions", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + }, + { + "id": "imp-video", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "multiple-impressions", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "tagid": "exco-banner-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + }, + { + "id": "imp-video", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "tagid": "exco-video-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["imp-banner", "imp-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "multiple-impressions", + "seatbid": [ + { + "bid": [ + { + "id": "imp-banner", + "impid": "imp-banner", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + }, + { + "id": "imp-video", + "impid": "imp-video", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + } + ], + "seat": "exco" + } + ], + "bidid": "multiple-impressions", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "imp-banner", + "impid": "imp-banner", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "imp-video", + "impid": "imp-video", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/exemplary/site-single-imp-banner.json b/adapters/exco/excotest/exemplary/site-single-imp-banner.json new file mode 100644 index 0000000000..be5b9c34d6 --- /dev/null +++ b/adapters/exco/excotest/exemplary/site-single-imp-banner.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "site-single-imp-banner", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "site-single-imp-banner_imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "site-single-imp-banner", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "site-single-imp-banner_imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "tagid": "exco-banner-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["site-single-imp-banner_imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "site-single-imp-banner", + "seatbid": [ + { + "bid": [ + { + "id": "site-single-imp-banner", + "impid": "site-single-imp-banner_imp", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + } + ], + "seat": "exco" + } + ], + "bidid": "site-single-imp-banner", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "site-single-imp-banner", + "impid": "site-single-imp-banner_imp", + "price": 1.5, + "adid": "8888", + "adm": "
Banner Ad
", + "cid": "4001", + "crid": "8888", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/exemplary/site-single-imp-video.json b/adapters/exco/excotest/exemplary/site-single-imp-video.json new file mode 100644 index 0000000000..817f9b0b26 --- /dev/null +++ b/adapters/exco/excotest/exemplary/site-single-imp-video.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "site-single-imp-video", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "site-single-imp-video_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "site-single-imp-video", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [{ + "id": "site-single-imp-video_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "tagid": "exco-video-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + }] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["site-single-imp-video_imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "site-single-imp-video", + "seatbid": [ + { + "bid": [ + { + "id": "site-single-imp-video_imp", + "impid": "site-single-imp-video_imp", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + } + ], + "seat": "exco" + } + ], + "bidid": "site-single-imp-video", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "site-single-imp-video_imp", + "impid": "site-single-imp-video_imp", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/supplemental/204-bid-response.json b/adapters/exco/excotest/supplemental/204-bid-response.json new file mode 100644 index 0000000000..a732d25030 --- /dev/null +++ b/adapters/exco/excotest/supplemental/204-bid-response.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "exco-test", + "site": { + "page": "prebid.org", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "204-bid-response_imp", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "exco-test", + "site": { + "page": "prebid.org", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [{ + "id": "204-bid-response_imp", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "tagid": "exco-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + }] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["204-bid-response_imp"] + }, + "mockResponse": { + "status": 204, + "body" : {} + } + } + ], + + "expectedBidResponses": [] +} + diff --git a/adapters/exco/excotest/supplemental/503-bid-response.json b/adapters/exco/excotest/supplemental/503-bid-response.json new file mode 100644 index 0000000000..34035f6f3b --- /dev/null +++ b/adapters/exco/excotest/supplemental/503-bid-response.json @@ -0,0 +1,78 @@ +{ + "mockBidRequest": { + "id": "exco-test", + "site": { + "page": "prebid.org", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "503-bid-response_imp", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "exco-test", + "site": { + "page": "prebid.org", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [{ + "id": "503-bid-response_imp", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "tagid": "exco-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + }] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["503-bid-response_imp"] + }, + "mockResponse": { + "status": 503, + "body" : {} + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/exco/excotest/supplemental/invalid-imp-ext-format.json b/adapters/exco/excotest/supplemental/invalid-imp-ext-format.json new file mode 100644 index 0000000000..359a085530 --- /dev/null +++ b/adapters/exco/excotest/supplemental/invalid-imp-ext-format.json @@ -0,0 +1,18 @@ +{ + "mockBidRequest": { + "id": "invalid-imp-ext-format", + "imp": [ + { + "id": "invalid-imp-ext-format", + "ext": "123" + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext for impression index 0. Error Information: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/exco/excotest/supplemental/invalid-imp-ext.json b/adapters/exco/excotest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..809f682aeb --- /dev/null +++ b/adapters/exco/excotest/supplemental/invalid-imp-ext.json @@ -0,0 +1,20 @@ +{ + "mockBidRequest": { + "id": "invalid-imp-ext", + "imp": [ + { + "id": "invalid-imp-ext-imp", + "ext": { + "bidder": "invalid" + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext.bidder for impression index 0. Error Information: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/exco/excotest/supplemental/invalid-response-body.json b/adapters/exco/excotest/supplemental/invalid-response-body.json new file mode 100644 index 0000000000..24145870f0 --- /dev/null +++ b/adapters/exco/excotest/supplemental/invalid-response-body.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "invalid-response-body", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "invalid-response-body-imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "invalid-response-body", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "invalid-response-body-imp", + "banner": { + "format": [ + { "w": 300, "h": 250 }, + { "w": 728, "h": 90 } + ] + }, + "tagid": "exco-banner-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-banner-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["invalid-response-body-imp"] + }, + "mockResponse": { + "status": 200, + "body": "{invalid_json_format}" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/exco/excotest/supplemental/mediaType_error.json b/adapters/exco/excotest/supplemental/mediaType_error.json new file mode 100644 index 0000000000..88a33b0b0c --- /dev/null +++ b/adapters/exco/excotest/supplemental/mediaType_error.json @@ -0,0 +1,112 @@ + +{ + "mockBidRequest": { + "id": "mediaType_error", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "mediaType_error_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "mediaType_error", + "site": { + "page": "example.com", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [{ + "id": "mediaType_error_imp", + "video": { + "mimes": ["video/mp4", "video/webm"], + "w": 640, + "h": 360, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3] + }, + "tagid": "exco-video-tagId", + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-video-tagId" + } + } + }] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["mediaType_error_imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "mediaType_error", + "seatbid": [ + { + "bid": [ + { + "id": "mediaType_error_imp", + "price": 2.5, + "adid": "9999", + "adm": "", + "cid": "5001", + "crid": "9999", + "mtype": 3 + } + ], + "seat": "exco" + } + ], + "bidid": "mediaType_error", + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "unrecognized bid_ad_type in response from exco: 3", + "comparison": "literal" + } + ] +} diff --git a/adapters/exco/excotest/supplemental/missing-publisher-app.json b/adapters/exco/excotest/supplemental/missing-publisher-app.json new file mode 100644 index 0000000000..cd9a0c5aab --- /dev/null +++ b/adapters/exco/excotest/supplemental/missing-publisher-app.json @@ -0,0 +1,106 @@ +{ + "mockBidRequest": { + "id": "missing-publisher-app-success", + "app": { + "id": "test-app-id" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "missing-publisher-app-success", + "app": { + "id": "test-app-id", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "tagid": "exco-tagId", + "ext": { + "bidder": { + "publisherId": "exco-publisherId", + "accountId": "exco-accountId", + "tagId": "exco-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "missing-publisher-app-success", + "seatbid": [ + { + "bid": [ + { + "id": "test-imp-id", + "impid": "test-imp-id", + "price": 1.5, + "adid": "1234", + "adm": "Ad Content", + "cid": "5678", + "crid": "1234", + "mtype": 1 + } + ], + "seat": "exco" + } + ], + "bidid": "missing-publisher-app-success", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-imp-id", + "impid": "test-imp-id", + "price": 1.5, + "adid": "1234", + "adm": "Ad Content", + "cid": "5678", + "crid": "1234", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/exco/excotest/supplemental/missing-publisher-site.json b/adapters/exco/excotest/supplemental/missing-publisher-site.json new file mode 100644 index 0000000000..78f4a06d8d --- /dev/null +++ b/adapters/exco/excotest/supplemental/missing-publisher-site.json @@ -0,0 +1,106 @@ +{ + "mockBidRequest": { + "id": "missing-publisher-site-success", + "site": { + "id": "test-site-id" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "accountId": "exco-accountId", + "publisherId": "exco-publisherId", + "tagId": "exco-tagId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body": { + "id": "missing-publisher-site-success", + "site": { + "id": "test-site-id", + "publisher": { + "id": "exco-publisherId" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "tagid": "exco-tagId", + "ext": { + "bidder": { + "publisherId": "exco-publisherId", + "accountId": "exco-accountId", + "tagId": "exco-tagId" + } + } + } + ] + }, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "missing-publisher-site-success", + "seatbid": [ + { + "bid": [ + { + "id": "test-imp-id", + "impid": "test-imp-id", + "price": 1.5, + "adid": "1234", + "adm": "Ad Content", + "cid": "5678", + "crid": "1234", + "mtype": 1 + } + ], + "seat": "exco" + } + ], + "bidid": "missing-publisher-site-success", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-imp-id", + "impid": "test-imp-id", + "price": 1.5, + "adid": "1234", + "adm": "Ad Content", + "cid": "5678", + "crid": "1234", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/exco/params_test.go b/adapters/exco/params_test.go new file mode 100644 index 0000000000..eed4bc4b64 --- /dev/null +++ b/adapters/exco/params_test.go @@ -0,0 +1,62 @@ +package exco + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/exco.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.exco + +// TestValidParams makes sure that the exco schema accepts all imp.ext fields which we intend to support. +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.BidderExco, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected exco params: %s \n Error: %s", validParam, err) + } + } +} + +// TestInvalidParams makes sure that the exco schema rejects all the imp.ext fields we don't support. +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.BidderExco, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"accountId":"73","publisherId":"1","tagId":"2"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"accountId":""}`, + `{"accountId":"","publisherId":""}`, + `{"accountId":"","publisherId":"","tagId":""}`, + `{"accountId":"73","publisherId":"2"}`, + `{"accountId":"73","siteId":"1","pageId":"2","formatId":"3"}`, + `{"siteId":1,"publisherId":2,"tagId":3}`, + `{"accountId":73,"pageId":2,"tagId":3}`, + `{"accountId":73,"tagId":1}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index efc8f51482..f7920a7e7c 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -101,6 +101,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/eplanning" "github.com/prebid/prebid-server/v3/adapters/epom" "github.com/prebid/prebid-server/v3/adapters/escalax" + "github.com/prebid/prebid-server/v3/adapters/exco" "github.com/prebid/prebid-server/v3/adapters/feedad" "github.com/prebid/prebid-server/v3/adapters/flatads" "github.com/prebid/prebid-server/v3/adapters/flipp" @@ -360,6 +361,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEPlanning: eplanning.Builder, openrtb_ext.BidderEpom: epom.Builder, openrtb_ext.BidderEscalax: escalax.Builder, + openrtb_ext.BidderExco: exco.Builder, openrtb_ext.BidderEVolution: evolution.Builder, openrtb_ext.BidderFeedAd: feedad.Builder, openrtb_ext.BidderFlatads: flatads.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 5eb322826c..be86afd66a 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -118,6 +118,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderEpom, BidderEscalax, BidderEVolution, + BidderExco, BidderFeedAd, BidderFlatads, BidderFlipp, @@ -483,6 +484,7 @@ const ( BidderEPlanning BidderName = "eplanning" BidderEpom BidderName = "epom" BidderEscalax BidderName = "escalax" + BidderExco BidderName = "exco" BidderEVolution BidderName = "e_volution" BidderFeedAd BidderName = "feedad" BidderFlatads BidderName = "flatads" diff --git a/openrtb_ext/imp_exco.go b/openrtb_ext/imp_exco.go new file mode 100644 index 0000000000..1ce97cbaa3 --- /dev/null +++ b/openrtb_ext/imp_exco.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ImpExtExco struct { + TagId string `json:"tagId"` + AccountId string `json:"accountId"` + PublisherId string `json:"publisherId"` +} diff --git a/static/bidder-info/exco.yaml b/static/bidder-info/exco.yaml new file mode 100644 index 0000000000..23c8a1d9e5 --- /dev/null +++ b/static/bidder-info/exco.yaml @@ -0,0 +1,18 @@ +endpoint: "https://v.ex.co/se/openrtb/hb/pbs" +maintainer: + email: "itadmin@ex.co" +gvlVendorID: 444 +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + key: "exco" + redirect: + url: "https://sync.ex.co/v1/user_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "[UID]" diff --git a/static/bidder-params/exco.json b/static/bidder-params/exco.json new file mode 100644 index 0000000000..724c75b9fd --- /dev/null +++ b/static/bidder-params/exco.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "The Exco Adapter Params", + "description": "A schema which validates params accepted by Exco adapter", + "type": "object", + "properties": { + "accountId": { + "type": "string", + "minLength": 1, + "description": "A unique account identifier provided by EX.CO." + }, + "publisherId": { + "type": "string", + "minLength": 1, + "description": "Publisher ID provided by EX.CO." + }, + "tagId": { + "type": "string", + "minLength": 1, + "description": "A unique Tag ID (supply id) identifier provided by EX.CO." + } + }, + "required": ["accountId", "publisherId", "tagId"] +} From f2f0f61db9e05b71751e27b6a3aa553f0da631e4 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Wed, 16 Jul 2025 08:43:01 +0530 Subject: [PATCH 025/272] Floors: Fix panic while getting adunit code for signaling (#4424) --- floors/rule.go | 2 +- floors/rule_test.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/floors/rule.go b/floors/rule.go index 65ddf31e72..189c765d30 100644 --- a/floors/rule.go +++ b/floors/rule.go @@ -421,7 +421,7 @@ func getAdUnitCode(imp *openrtb_ext.ImpWrapper) string { } prebidExt := impExt.GetPrebid() - if prebidExt != nil && prebidExt.StoredRequest.ID != "" { + if prebidExt != nil && prebidExt.StoredRequest != nil && prebidExt.StoredRequest.ID != "" { return prebidExt.StoredRequest.ID } } diff --git a/floors/rule_test.go b/floors/rule_test.go index d356a76823..dc46e05993 100644 --- a/floors/rule_test.go +++ b/floors/rule_test.go @@ -958,6 +958,11 @@ func TestGetAdUnitCode(t *testing.T) { imp: &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{}}, want: "*", }, + { + name: "empty_imp.ext.prebid.storedrequest.id", + imp: &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{Ext: json.RawMessage(`{"prebid": {"custom":{"id":"123"}}}`)}}, + want: "*", + }, } for _, tt := range tests { From efda9d50330c0c9455337eaa76be11bb415a21f8 Mon Sep 17 00:00:00 2001 From: Philip Watson Date: Thu, 17 Jul 2025 06:12:07 +1200 Subject: [PATCH 026/272] Stroeercore: Add adomain to bids (#4392) --- adapters/stroeerCore/stroeercore.go | 36 ++++++++++--------- .../exemplary/mobile-banner-single.json | 6 ++-- .../exemplary/site-banner-multi.json | 13 ++++--- .../exemplary/site-banner-single.json | 6 ++-- .../exemplary/site-multi-types.json | 12 ++++--- .../exemplary/site-video-single.json | 6 ++-- 6 files changed, 48 insertions(+), 31 deletions(-) diff --git a/adapters/stroeerCore/stroeercore.go b/adapters/stroeerCore/stroeercore.go index 1d503726eb..57dc2b0cd7 100644 --- a/adapters/stroeerCore/stroeercore.go +++ b/adapters/stroeerCore/stroeercore.go @@ -24,15 +24,16 @@ type response struct { } type bidResponse struct { - ID string `json:"id"` - BidID string `json:"bidId"` - CPM float64 `json:"cpm"` - Width int64 `json:"width"` - Height int64 `json:"height"` - Ad string `json:"ad"` - CrID string `json:"crid"` - Mtype string `json:"mtype"` - DSA json.RawMessage `json:"dsa"` + ID string `json:"id"` + BidID string `json:"bidId"` + CPM float64 `json:"cpm"` + Width int64 `json:"width"` + Height int64 `json:"height"` + Ad string `json:"ad"` + CrID string `json:"crid"` + Mtype string `json:"mtype"` + DSA json.RawMessage `json:"dsa"` + ADomain []string `json:"adomain,omitempty"` } type bidExt struct { @@ -78,14 +79,15 @@ func (a *adapter) MakeBids(bidRequest *openrtb2.BidRequest, requestData *adapter } openRtbBid := openrtb2.Bid{ - ID: bid.ID, - ImpID: bid.BidID, - W: bid.Width, - H: bid.Height, - Price: bid.CPM, - AdM: bid.Ad, - CrID: bid.CrID, - MType: markupType, + ID: bid.ID, + ImpID: bid.BidID, + W: bid.Width, + H: bid.Height, + Price: bid.CPM, + AdM: bid.Ad, + CrID: bid.CrID, + MType: markupType, + ADomain: bid.ADomain, } if bid.DSA != nil { diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json b/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json index 3cff0a2842..f45059f36a 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/mobile-banner-single.json @@ -163,7 +163,8 @@ "height": 60, "ad": "advert", "crid": "XYZijk", - "mtype": "banner" + "mtype": "banner", + "adomain": ["test.com", "example.com"] } ] } @@ -182,7 +183,8 @@ "w": 468, "h": 60, "crid": "XYZijk", - "mtype": 1 + "mtype": 1, + "adomain": ["test.com", "example.com"] }, "type": "banner" }] diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json index ad6e4d5f37..a753633337 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-multi.json @@ -140,7 +140,8 @@ "height": 60, "ad": "advert", "crid": "qwert", - "mtype": "banner" + "mtype": "banner", + "adomain": ["test.com"] }, { "id": "3929239282-02", @@ -150,7 +151,8 @@ "height": 250, "ad": "another advert", "crid": "wasd", - "mtype": "banner" + "mtype": "banner", + "adomain": ["example.com"] } ] } @@ -170,7 +172,8 @@ "w": 468, "h": 60, "crid": "qwert", - "mtype": 1 + "mtype": 1, + "adomain": ["test.com"] }, "type": "banner" }, @@ -183,7 +186,9 @@ "w": 770, "h": 250, "crid": "wasd", - "mtype": 1 + "mtype": 1, + "adomain": ["example.com"] + }, "type": "banner" } diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json index 1cc339732f..60622b6ced 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-banner-single.json @@ -107,7 +107,8 @@ "height": 60, "ad": "advert", "crid": "wasd", - "mtype": "banner" + "mtype": "banner", + "adomain": ["test.com"] } ] } @@ -126,7 +127,8 @@ "w": 468, "h": 60, "crid": "wasd", - "mtype": 1 + "mtype": 1, + "adomain": ["test.com"] }, "type": "banner" }] diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-multi-types.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-multi-types.json index 71bcec598c..0453f140a6 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/site-multi-types.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-multi-types.json @@ -134,7 +134,8 @@ "height": 60, "ad": "banner ad", "crid": "qwert", - "mtype": "banner" + "mtype": "banner", + "adomain": ["example.com"] }, { "id": "3929239282-02", @@ -144,7 +145,8 @@ "height": 250, "ad": "video ad", "crid": "wasd", - "mtype": "video" + "mtype": "video", + "adomain": ["test.com"] } ] } @@ -164,7 +166,8 @@ "w": 468, "h": 60, "crid": "qwert", - "mtype": 1 + "mtype": 1, + "adomain": ["example.com"] }, "type": "banner" }, @@ -177,7 +180,8 @@ "w": 770, "h": 250, "crid": "wasd", - "mtype": 2 + "mtype": 2, + "adomain": ["test.com"] }, "type": "video" } diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/site-video-single.json b/adapters/stroeerCore/stroeercoretest/exemplary/site-video-single.json index b78fbcbe44..12759e9091 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/site-video-single.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/site-video-single.json @@ -91,7 +91,8 @@ "cpm": 2, "ad": "
video
", "crid": "wasd", - "mtype": "video" + "mtype": "video", + "adomain": ["example.com"] } ] } @@ -108,7 +109,8 @@ "price": 2, "adm": "
video
", "crid": "wasd", - "mtype": 2 + "mtype": 2, + "adomain": ["example.com"] }, "type": "video" }] From 2b15320e5d06065f957c0faffcd2de29d6195a47 Mon Sep 17 00:00:00 2001 From: Vladimir Fedoseev Date: Wed, 16 Jul 2025 21:20:53 +0200 Subject: [PATCH 027/272] VIS.X: Relay bid currency from bid response (#4381) --- adapters/visx/visx.go | 6 ++++++ adapters/visx/visxtest/exemplary/headers_ipv4.json | 2 +- adapters/visx/visxtest/exemplary/headers_ipv6.json | 2 +- .../visx/visxtest/exemplary/multitype-banner-response.json | 2 +- .../visx/visxtest/exemplary/multitype-video-response.json | 2 +- adapters/visx/visxtest/exemplary/simple-banner.json | 2 +- adapters/visx/visxtest/exemplary/simple-video.json | 2 +- adapters/visx/visxtest/exemplary/with_currency.json | 2 +- adapters/visx/visxtest/supplemental/wrong_imp_type.json | 2 +- adapters/visx/visxtest/supplemental/wrong_impid.json | 2 +- static/bidder-info/visx.yaml | 2 +- 11 files changed, 16 insertions(+), 10 deletions(-) diff --git a/adapters/visx/visx.go b/adapters/visx/visx.go index 85f3c300a2..36f62ab298 100644 --- a/adapters/visx/visx.go +++ b/adapters/visx/visx.go @@ -49,6 +49,7 @@ type visxSeatBid struct { type visxResponse struct { SeatBid []visxSeatBid `json:"seatbid,omitempty"` + Cur string `json:"cur,omitempty"` } // MakeRequests makes the HTTP requests which should be made to fetch bids. @@ -139,6 +140,11 @@ func (a *VisxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalReq }) } } + + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } + return bidResponse, nil } diff --git a/adapters/visx/visxtest/exemplary/headers_ipv4.json b/adapters/visx/visxtest/exemplary/headers_ipv4.json index 206ba6bce9..6f9ff1a18f 100644 --- a/adapters/visx/visxtest/exemplary/headers_ipv4.json +++ b/adapters/visx/visxtest/exemplary/headers_ipv4.json @@ -131,7 +131,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/headers_ipv6.json b/adapters/visx/visxtest/exemplary/headers_ipv6.json index 577d232171..074cf3bacb 100644 --- a/adapters/visx/visxtest/exemplary/headers_ipv6.json +++ b/adapters/visx/visxtest/exemplary/headers_ipv6.json @@ -131,7 +131,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/multitype-banner-response.json b/adapters/visx/visxtest/exemplary/multitype-banner-response.json index 2ea4030dbc..6c94b64059 100644 --- a/adapters/visx/visxtest/exemplary/multitype-banner-response.json +++ b/adapters/visx/visxtest/exemplary/multitype-banner-response.json @@ -139,7 +139,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/multitype-video-response.json b/adapters/visx/visxtest/exemplary/multitype-video-response.json index 9beab780bd..55cfcfa196 100644 --- a/adapters/visx/visxtest/exemplary/multitype-video-response.json +++ b/adapters/visx/visxtest/exemplary/multitype-video-response.json @@ -139,7 +139,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/simple-banner.json b/adapters/visx/visxtest/exemplary/simple-banner.json index 6971f4e5f4..83c6087e09 100644 --- a/adapters/visx/visxtest/exemplary/simple-banner.json +++ b/adapters/visx/visxtest/exemplary/simple-banner.json @@ -127,7 +127,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/simple-video.json b/adapters/visx/visxtest/exemplary/simple-video.json index 21a66f464a..1962bd4450 100644 --- a/adapters/visx/visxtest/exemplary/simple-video.json +++ b/adapters/visx/visxtest/exemplary/simple-video.json @@ -127,7 +127,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/exemplary/with_currency.json b/adapters/visx/visxtest/exemplary/with_currency.json index 35698ed86b..8815e87191 100644 --- a/adapters/visx/visxtest/exemplary/with_currency.json +++ b/adapters/visx/visxtest/exemplary/with_currency.json @@ -50,7 +50,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["EUR"], + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/visx/visxtest/supplemental/wrong_imp_type.json b/adapters/visx/visxtest/supplemental/wrong_imp_type.json index dd3ce10f14..fafc0aac0b 100644 --- a/adapters/visx/visxtest/supplemental/wrong_imp_type.json +++ b/adapters/visx/visxtest/supplemental/wrong_imp_type.json @@ -44,7 +44,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [{ "seat": "51", "bid": [{ diff --git a/adapters/visx/visxtest/supplemental/wrong_impid.json b/adapters/visx/visxtest/supplemental/wrong_impid.json index 6052ac2625..d99bfd4052 100644 --- a/adapters/visx/visxtest/supplemental/wrong_impid.json +++ b/adapters/visx/visxtest/supplemental/wrong_impid.json @@ -52,7 +52,7 @@ "mockResponse": { "status": 200, "body": { - "cur": ["USD"], + "cur": "USD", "seatbid": [{ "seat": "51", "bid": [{ diff --git a/static/bidder-info/visx.yaml b/static/bidder-info/visx.yaml index b2acafaaed..655477452b 100644 --- a/static/bidder-info/visx.yaml +++ b/static/bidder-info/visx.yaml @@ -1,4 +1,4 @@ -endpoint: "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.1" +endpoint: "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.2" maintainer: email: "supply.partners@yoc.com" gvlVendorID: 154 From c4884eafc0891ab4ae77bf3c2a30f72a0a326325 Mon Sep 17 00:00:00 2001 From: Veronika Solovei Date: Thu, 17 Jul 2025 09:34:19 -0400 Subject: [PATCH 028/272] TMax: Add default host config (#4430) --- config/config.go | 3 +++ config/config_test.go | 4 ++++ endpoints/openrtb2/amp_auction.go | 2 +- endpoints/openrtb2/auction.go | 2 +- endpoints/openrtb2/video_auction.go | 2 +- go.mod | 2 +- ortb/default.go | 6 +++++- ortb/default_test.go | 15 ++++++++++++++- 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index 3a2e05179e..422af3d440 100644 --- a/config/config.go +++ b/config/config.go @@ -39,6 +39,7 @@ type Configuration struct { StatusResponse string `mapstructure:"status_response"` AuctionTimeouts AuctionTimeouts `mapstructure:"auction_timeouts_ms"` TmaxAdjustments TmaxAdjustments `mapstructure:"tmax_adjustments"` + TmaxDefault int `mapstructure:"tmax_default"` CacheURL Cache `mapstructure:"cache"` ExtCacheURL ExternalCache `mapstructure:"external_cache"` RecaptchaSecret string `mapstructure:"recaptcha_secret"` @@ -1210,6 +1211,8 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("tmax_adjustments.bidder_network_latency_buffer_ms", 0) v.SetDefault("tmax_adjustments.pbs_response_preparation_duration_ms", 0) + v.SetDefault("tmax_default", 0) + /* IPv4 /* Site Local: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 /* Link Local: 169.254.0.0/16 diff --git a/config/config_test.go b/config/config_test.go index a2453d718b..d1493afce0 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -227,6 +227,8 @@ func TestDefaults(t *testing.T) { cmpUnsignedInts(t, "tmax_adjustments.bidder_network_latency_buffer_ms", 0, cfg.TmaxAdjustments.BidderNetworkLatencyBuffer) cmpUnsignedInts(t, "tmax_adjustments.pbs_response_preparation_duration_ms", 0, cfg.TmaxAdjustments.PBSResponsePreparationDuration) + cmpInts(t, "tmax_default", 0, cfg.TmaxDefault) + cmpInts(t, "account_defaults.privacy.ipv6.anon_keep_bits", 56, cfg.AccountDefaults.Privacy.IPv6Config.AnonKeepBits) cmpInts(t, "account_defaults.privacy.ipv4.anon_keep_bits", 24, cfg.AccountDefaults.Privacy.IPv4Config.AnonKeepBits) @@ -549,6 +551,7 @@ tmax_adjustments: bidder_response_duration_min_ms: 700 bidder_network_latency_buffer_ms: 100 pbs_response_preparation_duration_ms: 100 +tmax_default: 600 analytics: agma: enabled: true @@ -650,6 +653,7 @@ func TestFullConfig(t *testing.T) { cmpUnsignedInts(t, "tmax_adjustments.bidder_response_duration_min_ms", 700, cfg.TmaxAdjustments.BidderResponseDurationMin) cmpUnsignedInts(t, "tmax_adjustments.bidder_network_latency_buffer_ms", 100, cfg.TmaxAdjustments.BidderNetworkLatencyBuffer) cmpUnsignedInts(t, "tmax_adjustments.pbs_response_preparation_duration_ms", 100, cfg.TmaxAdjustments.PBSResponsePreparationDuration) + cmpInts(t, "tmax_default", 600, cfg.TmaxDefault) //Assert the price floor values cmpBools(t, "price_floors.enabled", true, cfg.PriceFloors.Enabled) diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 6f37d49fca..9bf4c6ab61 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -524,7 +524,7 @@ func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openr return } - if err := ortb.SetDefaults(req); err != nil { + if err := ortb.SetDefaults(req, deps.cfg.TmaxDefault); err != nil { errs = append(errs, err) return } diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 84835f0bf1..68548d5b87 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -550,7 +550,7 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metric errs = append(errs, errsL...) } - if err := ortb.SetDefaults(req); err != nil { + if err := ortb.SetDefaults(req, deps.cfg.TmaxDefault); err != nil { errs = []error{err} return } diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index 50b54c5b33..0bad62124d 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -265,7 +265,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re return } - if err := ortb.SetDefaults(bidReqWrapper); err != nil { + if err := ortb.SetDefaults(bidReqWrapper, deps.cfg.TmaxDefault); err != nil { handleError(&labels, w, errL, &vo, &debugLog) return } diff --git a/go.mod b/go.mod index da0f47998e..fd9bb2b396 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/julienschmidt/httprouter v1.3.0 github.com/lib/pq v1.10.4 github.com/mitchellh/copystructure v1.2.0 + github.com/mitchellh/mapstructure v1.5.0 github.com/modern-go/reflect2 v1.0.2 github.com/prebid/go-gdpr v1.12.0 github.com/prebid/go-gpp v0.2.0 @@ -57,7 +58,6 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/pelletier/go-toml v1.9.5 // indirect diff --git a/ortb/default.go b/ortb/default.go index ed2523b147..f6cc979045 100644 --- a/ortb/default.go +++ b/ortb/default.go @@ -12,7 +12,7 @@ const ( DefaultSecure = int8(1) ) -func SetDefaults(r *openrtb_ext.RequestWrapper) error { +func SetDefaults(r *openrtb_ext.RequestWrapper, defaultTmax int) error { requestExt, err := r.GetRequestExt() if err != nil { return err @@ -36,6 +36,10 @@ func SetDefaults(r *openrtb_ext.RequestWrapper) error { } } + if r.TMax == 0 { + r.TMax = int64(defaultTmax) + } + return nil } diff --git a/ortb/default_test.go b/ortb/default_test.go index fd77ba4c54..b03f546fd4 100644 --- a/ortb/default_test.go +++ b/ortb/default_test.go @@ -22,6 +22,7 @@ func TestSetDefaults(t *testing.T) { name string givenRequest openrtb2.BidRequest expectedRequest openrtb2.BidRequest + tMax int expectedErr string }{ { @@ -45,6 +46,18 @@ func TestSetDefaults(t *testing.T) { givenRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}, {Secure: nil}}}, expectedRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}, {Secure: &secure1}}}, }, + { + name: "tmax_not_set_should_be_set_to_default", // tests integration with setDefaultsImp + givenRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}}, TMax: 0}, + expectedRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}}, TMax: 100}, + tMax: 100, + }, + { + name: "tmax_set_should_remain_the_same", // tests integration with setDefaultsImp + givenRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}}, TMax: 200}, + expectedRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}}, TMax: 200}, + tMax: 100, + }, } for _, test := range testCases { @@ -52,7 +65,7 @@ func TestSetDefaults(t *testing.T) { wrapper := &openrtb_ext.RequestWrapper{BidRequest: &test.givenRequest} // run - err := SetDefaults(wrapper) + err := SetDefaults(wrapper, test.tMax) // assert error if len(test.expectedErr) > 0 { From 8b17f7b7eeff8d40ebe71bea1f7519d6d16be75a Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:34:20 -0700 Subject: [PATCH 029/272] Fix the package (iterators) to agree with the dir (iterutil). (#4447) --- util/iterutil/doc.go | 8 ++++---- util/iterutil/gjson.go | 2 +- util/iterutil/gjson_test.go | 2 +- util/iterutil/iter.go | 2 +- util/iterutil/iter_test.go | 2 +- util/iterutil/slices.go | 2 +- util/iterutil/slices_test.go | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/util/iterutil/doc.go b/util/iterutil/doc.go index c46b5c0119..4b32500112 100644 --- a/util/iterutil/doc.go +++ b/util/iterutil/doc.go @@ -1,5 +1,5 @@ /* -Package iterators provides a set of iterators for various data structures. +Package iterutil provides a set of iterutil for various data structures. # Elements of slices as pointers @@ -15,14 +15,14 @@ In order to improve that, and also not have to use the throw-away `_` variable, iterate across pointers to each element in the slice: var myStructs []MyStruct - for myStructPtr := range iterators.SlicePointerValues(myStructs) { + for myStructPtr := range iterutil.SlicePointerValues(myStructs) { // myStructPtr is a pointer to each element - any changes in the loop will be reflected in the slice element. } If you still need the index, you can use [SlicePointers]: var myStructs []MyStruct - for i, myStructPtr := range iterators.SlicePointers(myStructs) { + for i, myStructPtr := range iterutil.SlicePointers(myStructs) { // myStructPtr is a pointer to each element - any changes in the loop will be reflected in the slice element. // i is the index of the element. } @@ -33,4 +33,4 @@ The https://github.com/tidwall/gjson library is already included as a dependency the [WalkGjsonLeaves] iterator is available, which will yield the json paths to all leaves in the document along with the [gjson.Result] for each leaf. */ -package iterators +package iterutil diff --git a/util/iterutil/gjson.go b/util/iterutil/gjson.go index 7d8cb7014b..6a1af2f71d 100644 --- a/util/iterutil/gjson.go +++ b/util/iterutil/gjson.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import ( "iter" diff --git a/util/iterutil/gjson_test.go b/util/iterutil/gjson_test.go index db77b09930..2c7e470a16 100644 --- a/util/iterutil/gjson_test.go +++ b/util/iterutil/gjson_test.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import ( "slices" diff --git a/util/iterutil/iter.go b/util/iterutil/iter.go index dabe05d7e2..108f6273cc 100644 --- a/util/iterutil/iter.go +++ b/util/iterutil/iter.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import "iter" diff --git a/util/iterutil/iter_test.go b/util/iterutil/iter_test.go index ce935d529d..4810729e85 100644 --- a/util/iterutil/iter_test.go +++ b/util/iterutil/iter_test.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import ( "iter" diff --git a/util/iterutil/slices.go b/util/iterutil/slices.go index 29e1616609..c942b9530c 100644 --- a/util/iterutil/slices.go +++ b/util/iterutil/slices.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import "iter" diff --git a/util/iterutil/slices_test.go b/util/iterutil/slices_test.go index 0c57a89fd2..1f30c8cef2 100644 --- a/util/iterutil/slices_test.go +++ b/util/iterutil/slices_test.go @@ -1,4 +1,4 @@ -package iterators +package iterutil import ( "testing" From f5183a66811d82abdcb9d9d1400448cff7d9279b Mon Sep 17 00:00:00 2001 From: andre-gielow-ttd <124626380+andre-gielow-ttd@users.noreply.github.com> Date: Wed, 23 Jul 2025 12:25:25 -0400 Subject: [PATCH 030/272] TheTradeDesk: Throw error for malformed endpoint url (#4419) --- adapters/thetradedesk/thetradedesk.go | 8 ++++---- adapters/thetradedesk/thetradedesk_test.go | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go index 47fb9ee0fd..2fdf227d15 100644 --- a/adapters/thetradedesk/thetradedesk.go +++ b/adapters/thetradedesk/thetradedesk.go @@ -17,8 +17,6 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" ) -//const PREBID_INTEGRATION_TYPE = "1" - type adapter struct { bidderEndpointTemplate string defaultEndpoint string @@ -87,13 +85,12 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E bidderEndpoint, err := a.buildEndpointURL(supplySourceId) if err != nil { - return nil, []error{errors.New("Failed to build endpoint URL")} + return nil, []error{err} } headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") - //headers.Add("x-integration-type", PREBID_INTEGRATION_TYPE) this will be parsed and added conditionally later return []*adapters.RequestData{{ Method: "POST", Uri: bidderEndpoint, @@ -105,6 +102,9 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E func (a *adapter) buildEndpointURL(supplySourceId string) (string, error) { if supplySourceId == "" { + if a.defaultEndpoint == "" { + return "", errors.New("Either supplySourceId or a default endpoint must be provided") + } return a.defaultEndpoint, nil } diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go index 42166c4b76..22fdcebeec 100644 --- a/adapters/thetradedesk/thetradedesk_test.go +++ b/adapters/thetradedesk/thetradedesk_test.go @@ -2,6 +2,7 @@ package thetradedesk import ( "encoding/json" + "errors" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "net/http" "testing" @@ -425,7 +426,7 @@ func TestTheTradeDeskAdapter_BuildEndpoint(t *testing.T) { supplySourceId: "", defaultEndpoint: "", expectedEndpoint: "", - wantErr: nil, + wantErr: []error{errors.New("Either supplySourceId or a default endpoint must be provided")}, }, } @@ -442,6 +443,9 @@ func TestTheTradeDeskAdapter_BuildEndpoint(t *testing.T) { finalEndpoint, err := a.buildEndpointURL(tt.supplySourceId) if tt.wantErr != nil { assert.NotNil(t, err) + assert.Equal(t, tt.wantErr[0].Error(), err.Error()) + } else { + assert.Nil(t, err) } assert.Equal(t, tt.expectedEndpoint, finalEndpoint) }) From dd6c3afc295c916308842c628c203203904612d0 Mon Sep 17 00:00:00 2001 From: Nathan Le Sommer Date: Thu, 24 Jul 2025 17:19:19 +0200 Subject: [PATCH 031/272] Smartadserver : Send multi-impression requests without flattening (#4402) Co-authored-by: nlesommer Co-authored-by: gtodeschi --- adapters/smartadserver/smartadserver.go | 30 ++++----- .../exemplary/multi-banner.json | 60 +----------------- .../multi-format-multi-imp-type.json | 63 +------------------ 3 files changed, 19 insertions(+), 134 deletions(-) diff --git a/adapters/smartadserver/smartadserver.go b/adapters/smartadserver/smartadserver.go index 8099f67834..837d46c725 100644 --- a/adapters/smartadserver/smartadserver.go +++ b/adapters/smartadserver/smartadserver.go @@ -59,7 +59,9 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf smartRequest.Site.Publisher = &publisher } - // We send one serialized "smartRequest" per impression of the original request. + var imps []openrtb2.Imp + + // Filter out impressions that do not have the proper bidder extensions for _, imp := range request.Imp { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { @@ -77,37 +79,34 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf continue } + imps = append(imps, imp) + // Adding publisher id. smartRequest.Site.Publisher.ID = strconv.Itoa(smartadserverExt.NetworkID) + } - // We send one request for each impression. - smartRequest.Imp = []openrtb2.Imp{imp} - - var errMarshal error - if imp.Ext, errMarshal = json.Marshal(smartadserverExt); errMarshal != nil { - errs = append(errs, &errortypes.BadInput{ - Message: errMarshal.Error(), - }) - continue - } + // Only create the request if it has at least one correctly formatted impression + if len(imps) != 0 { + smartRequest.Imp = imps reqJSON, err := json.Marshal(smartRequest) if err != nil { errs = append(errs, &errortypes.BadInput{ Message: "Error parsing reqJSON object", }) - continue + return nil, errs } - url, err := a.BuildEndpointURL(&smartadserverExt) + url, err := a.BuildEndpointURL() if url == "" { errs = append(errs, err) - continue + return nil, errs } headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") + adapterRequests = append(adapterRequests, &adapters.RequestData{ Method: "POST", Uri: url, @@ -116,6 +115,7 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf ImpIDs: openrtb_ext.GetImpIDs(smartRequest.Imp), }) } + return adapterRequests, errs } @@ -158,7 +158,7 @@ func (a *SmartAdserverAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex } // BuildEndpointURL : Builds endpoint url -func (a *SmartAdserverAdapter) BuildEndpointURL(params *openrtb_ext.ExtImpSmartadserver) (string, error) { +func (a *SmartAdserverAdapter) BuildEndpointURL() (string, error) { uri, err := url.Parse(a.host) if err != nil || uri.Scheme == "" || uri.Host == "" { return "", &errortypes.BadInput{ diff --git a/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json index a47da513b9..50ac6025a9 100644 --- a/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json +++ b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json @@ -53,45 +53,7 @@ "networkId": 73 } } - } - ], - "site": { - "publisher": { - "id": "73" - } - } - }, - "impIDs":["test-imp-id-1"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-multi-id", - "seatbid": [ - { - "seat": "smartadserver", - "bid": [{ - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id-1", - "price": 0.500000, - "adm": "some-test-ad", - "crid": "crid_10", - "mtype": 1, - "h": 90, - "w": 728 - }] - } - ], - "cur": "USD" - } - } - }, - { - "expectedRequest": { - "uri": "https://ssb.smartadserver.com/api/bid?callerId=5", - "body": { - "id": "test-request-multi-id", - "imp": [ + }, { "id": "test-imp-id-2", "banner": { @@ -113,7 +75,7 @@ } } }, - "impIDs":["test-imp-id-2"] + "impIDs":["test-imp-id-1","test-imp-id-2"] }, "mockResponse": { "status": 200, @@ -141,24 +103,6 @@ ], "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id-1", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "mtype": 1, - "w": 728, - "h": 90 - }, - "type": "banner" - } - ] - }, { "currency": "USD", "bids": [ diff --git a/adapters/smartadserver/smartadservertest/exemplary/multi-format-multi-imp-type.json b/adapters/smartadserver/smartadservertest/exemplary/multi-format-multi-imp-type.json index 11808bf3a8..5e3a450747 100644 --- a/adapters/smartadserver/smartadservertest/exemplary/multi-format-multi-imp-type.json +++ b/adapters/smartadserver/smartadservertest/exemplary/multi-format-multi-imp-type.json @@ -97,49 +97,7 @@ "networkId": 73 } } - } - ], - "site": { - "publisher": { - "id": "73" - } - } - }, - "impIDs": [ - "test-imp-id-1" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-multi-id", - "seatbid": [ - { - "seat": "smartadserver", - "bid": [ - { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id-1", - "price": 0.500000, - "adm": "some-test-ad", - "crid": "crid_10", - "mtype": 1, - "w": 728, - "h": 90 - } - ] - } - ], - "cur": "USD" - } - } - }, - { - "expectedRequest": { - "uri": "https://ssb.smartadserver.com/api/bid?callerId=5", - "body": { - "id": "test-request-multi-id", - "imp": [ + }, { "id": "test-imp-id-2", "banner": { @@ -177,6 +135,7 @@ } }, "impIDs": [ + "test-imp-id-1", "test-imp-id-2" ] }, @@ -207,24 +166,6 @@ } ], "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id-1", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "mtype": 1, - "w": 728, - "h": 90 - }, - "type": "banner" - } - ] - }, { "currency": "USD", "bids": [ From d34998d4df3ab2eab2af233294f258fe7f7533a6 Mon Sep 17 00:00:00 2001 From: Piotr Jaworski <109736938+piotrj-rtbh@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:10:34 +0200 Subject: [PATCH 032/272] RTB House: Remove PAAPI signals from imp[].ext (#4399) --- adapters/rtbhouse/rtbhouse.go | 32 +++++++ .../exemplary/simple-banner-paapi.json | 95 +++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json diff --git a/adapters/rtbhouse/rtbhouse.go b/adapters/rtbhouse/rtbhouse.go index f499022aa1..9a7e3f4f92 100644 --- a/adapters/rtbhouse/rtbhouse.go +++ b/adapters/rtbhouse/rtbhouse.go @@ -81,6 +81,15 @@ func (adapter *RTBHouseAdapter) MakeRequests( imp.BidFloor = bidFloor } + // remove PAAPI signals from imp.Ext. RTB House pauses PAAPI support, + // the bidder should not get any PAAPI signals + newImpExt, err := clearAuctionEnvironment(&imp) + if err != nil { + errs = append(errs, err) + return nil, errs + } + imp.Ext = newImpExt + // Set the CUR of bid to BIDDER_CURRENCY after converting all floors reqCopy.Cur = []string{BidderCurrency} reqCopy.Imp = append(reqCopy.Imp, imp) @@ -106,6 +115,29 @@ func (adapter *RTBHouseAdapter) MakeRequests( return requestsToBidder, errs } +func clearAuctionEnvironment(imp *openrtb2.Imp) (json.RawMessage, error) { + var objmap map[string]interface{} + err := json.Unmarshal(imp.Ext, &objmap) + if err != nil { + return nil, err + } + + keysToDelete := []string{"ae", "igs", "paapi"} + for _, key := range keysToDelete { + _, exists := objmap[key] + if exists { + delete(objmap, key) + } + } + + newImpExt, err := json.Marshal(objmap) + if err != nil { + return nil, err + } + + return newImpExt, nil +} + func getImpressionExt(imp openrtb2.Imp) (*openrtb_ext.ExtImpRTBHouse, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json new file mode 100644 index 0000000000..fb96bdff14 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://good.site/url" + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "ae": 1, + "bidder": {}, + "igs": { + "ae": 1, + "biddable": 1 + }, + "paapi": { + "somekey": "somevalue" + } + } + }] + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": ["USD"], + "site": { + "page": "https://good.site/url" + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": {} + } + }] + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "seat": "rtbhouse", + "bid": [{ + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }] + }], + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "12345678", + "cid": "987", + "crid": "12345678", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }] + }] +} From d949d79a9f43b7acf41a5199e7d3dc4cac32adfb Mon Sep 17 00:00:00 2001 From: sindhuja-sridharan <148382298+sindhuja-sridharan@users.noreply.github.com> Date: Thu, 24 Jul 2025 10:18:14 -0700 Subject: [PATCH 033/272] GumGum: Enable Opt-In change notification (#4390) --- .github/workflows/scripts/codepath-notification | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification index 2c1bb0fb9b..a86dccbbd7 100644 --- a/.github/workflows/scripts/codepath-notification +++ b/.github/workflows/scripts/codepath-notification @@ -17,3 +17,4 @@ pubmatic: header-bidding@pubmatic.com openx: prebid@openx.com adapters/ix|imp_ix|ix.json|ix.yaml: pdu-supply-prebid@indexexchange.com medianet: prebid@media.net +gumgum: prebid@gumgum.com From 03b2e67cce7a0443a0a51ef31c8230c34325c7cf Mon Sep 17 00:00:00 2001 From: jordi-tappx Date: Fri, 25 Jul 2025 05:02:21 +0200 Subject: [PATCH 034/272] Tappx: Add GPID support (#4438) Co-authored-by: Jordi Arnau --- adapters/tappx/tappx.go | 3 +- adapters/tappx/tappx_test.go | 2 +- .../single-banner-impression-extra.json | 2 +- ...ngle-banner-impression-future-feature.json | 2 +- .../exemplary/single-banner-impression.json | 2 +- .../exemplary/single-banner-site.json | 2 +- .../exemplary/single-video-impression.json | 2 +- .../exemplary/single-video-site.json | 2 +- .../tappxtest/supplemental/204status.json | 2 +- .../tappxtest/supplemental/bidfloor.json | 2 +- .../tappx/tappxtest/supplemental/gpid.json | 125 ++++++++++++++++++ .../supplemental/http-err-status.json | 2 +- .../supplemental/http-err-status2.json | 2 +- 13 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 adapters/tappx/tappxtest/supplemental/gpid.json diff --git a/adapters/tappx/tappx.go b/adapters/tappx/tappx.go index a0c6d9c7dd..71bad1543b 100644 --- a/adapters/tappx/tappx.go +++ b/adapters/tappx/tappx.go @@ -19,7 +19,7 @@ import ( "github.com/prebid/prebid-server/v3/util/jsonutil" ) -const TAPPX_BIDDER_VERSION = "1.5" +const TAPPX_BIDDER_VERSION = "1.6" const TYPE_CNN = "prebid" type TappxAdapter struct { @@ -35,6 +35,7 @@ type Bidder struct { type Ext struct { Bidder `json:"bidder"` + GPID string `json:"gpid,omitempty"` } // Builder builds a new instance of the Tappx adapter for the given bidder with the given config. diff --git a/adapters/tappx/tappx_test.go b/adapters/tappx/tappx_test.go index bf4e4f9f17..3643a58cc4 100644 --- a/adapters/tappx/tappx_test.go +++ b/adapters/tappx/tappx_test.go @@ -47,7 +47,7 @@ func TestTsValue(t *testing.T) { url, err := bidderTappx.buildEndpointURL(&tappxExt, test) require.NoError(t, err, "buildEndpointURL") - match, err := regexp.MatchString(`http://ssp\.api\.tappx\.com/rtb/v2/DUMMYENDPOINT\?tappxkey=dummy-tappx-key&ts=[0-9]{13}&type_cnn=prebid&v=1\.5`, url) + match, err := regexp.MatchString(`http://ssp\.api\.tappx\.com/rtb/v2/DUMMYENDPOINT\?tappxkey=dummy-tappx-key&ts=[0-9]{13}&type_cnn=prebid&v=1\.6`, url) if err != nil { t.Errorf("Error while running regex validation: %s", err.Error()) return diff --git a/adapters/tappx/tappxtest/exemplary/single-banner-impression-extra.json b/adapters/tappx/tappxtest/exemplary/single-banner-impression-extra.json index fc03a4daa2..35bfd860aa 100644 --- a/adapters/tappx/tappxtest/exemplary/single-banner-impression-extra.json +++ b/adapters/tappx/tappxtest/exemplary/single-banner-impression-extra.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/exemplary/single-banner-impression-future-feature.json b/adapters/tappx/tappxtest/exemplary/single-banner-impression-future-feature.json index 478e4ace29..fdd0d0ca21 100644 --- a/adapters/tappx/tappxtest/exemplary/single-banner-impression-future-feature.json +++ b/adapters/tappx/tappxtest/exemplary/single-banner-impression-future-feature.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://zz123456ps.pub.tappx.com/rtb/?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://zz123456ps.pub.tappx.com/rtb/?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/exemplary/single-banner-impression.json b/adapters/tappx/tappxtest/exemplary/single-banner-impression.json index 7028b7a4f4..5daee46b6d 100644 --- a/adapters/tappx/tappxtest/exemplary/single-banner-impression.json +++ b/adapters/tappx/tappxtest/exemplary/single-banner-impression.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/exemplary/single-banner-site.json b/adapters/tappx/tappxtest/exemplary/single-banner-site.json index ea9057f108..a6267c3f67 100644 --- a/adapters/tappx/tappxtest/exemplary/single-banner-site.json +++ b/adapters/tappx/tappxtest/exemplary/single-banner-site.json @@ -36,7 +36,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-site-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-site-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/exemplary/single-video-impression.json b/adapters/tappx/tappxtest/exemplary/single-video-impression.json index a63bc17ee7..6133b04a77 100644 --- a/adapters/tappx/tappxtest/exemplary/single-video-impression.json +++ b/adapters/tappx/tappxtest/exemplary/single-video-impression.json @@ -34,7 +34,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/VZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/VZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/exemplary/single-video-site.json b/adapters/tappx/tappxtest/exemplary/single-video-site.json index 60a8fdd9a9..1e275aca9c 100644 --- a/adapters/tappx/tappxtest/exemplary/single-video-site.json +++ b/adapters/tappx/tappxtest/exemplary/single-video-site.json @@ -38,7 +38,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/VZ123456PS?tappxkey=pub-12345-site-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/VZ123456PS?tappxkey=pub-12345-site-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/supplemental/204status.json b/adapters/tappx/tappxtest/supplemental/204status.json index a6b2a49b68..4af05d0ad9 100644 --- a/adapters/tappx/tappxtest/supplemental/204status.json +++ b/adapters/tappx/tappxtest/supplemental/204status.json @@ -29,7 +29,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/supplemental/bidfloor.json b/adapters/tappx/tappxtest/supplemental/bidfloor.json index 44a1712d3c..8f42d53e86 100644 --- a/adapters/tappx/tappxtest/supplemental/bidfloor.json +++ b/adapters/tappx/tappxtest/supplemental/bidfloor.json @@ -33,7 +33,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/supplemental/gpid.json b/adapters/tappx/tappxtest/supplemental/gpid.json new file mode 100644 index 0000000000..57f9105efe --- /dev/null +++ b/adapters/tappx/tappxtest/supplemental/gpid.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "0000000000002", + "test": 1, + "imp": [ + { + "id": "adunit-1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "tappxkey": "pub-12345-android-9876", + "endpoint": "ZZ123456PS", + "bidfloor": 1.5 + }, + "gpid": "/19968336/header-bid-tag-0" + } + } + ], + "app": { + "id": "app_001", + "bundle": "com.rovio.angrybirds", + "publisher": { + "id": "2" + } + }, + "user": { + "buyeruid": "A-38327932832" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", + "body": { + "id": "0000000000002", + "test": 1, + "imp": [ + { + "id": "adunit-1", + "banner": { + "w": 300, + "h": 250 + }, + "bidfloor": 1.5, + "ext": { + "bidder": { + "bidfloor": 1.5, + "tappxkey": "pub-12345-android-9876", + "endpoint": "ZZ123456PS" + }, + "gpid": "/19968336/header-bid-tag-0" + } + } + ], + "app": { + "bundle": "com.rovio.angrybirds", + "id": "app_001", + "publisher": { + "id": "2" + } + }, + "user": { + "buyeruid": "A-38327932832" + }, + "ext": { + "bidder": { + "tappxkey": "pub-12345-android-9876" + } + } + }, + "impIDs":["adunit-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "75472df2-1cb3-4f8e-9a28-10cb95fe05a4", + "seatbid": [{ + "bid": [{ + "id": "wehM-93KGr0_0_0", + "impid": "adunit-1", + "price": 0.5, + "cid": "3706", + "crid": "19005", + "adid": "19005", + "adm": "", + "cat": ["IAB2"], + "adomain": ["test.com"], + "h": 250, + "w": 300 + }] + }], + "bidid": "wehM-93KGr0" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "wehM-93KGr0_0_0", + "impid": "adunit-1", + "price": 0.5, + "adm": "", + "adid": "19005", + "adomain": ["test.com"], + "cid": "3706", + "crid": "19005", + "w": 300, + "h": 250, + "cat": ["IAB2"] + }, + "type": "banner" + } + ] + } + ] + } \ No newline at end of file diff --git a/adapters/tappx/tappxtest/supplemental/http-err-status.json b/adapters/tappx/tappxtest/supplemental/http-err-status.json index e8b1a2e532..069b01e3a7 100644 --- a/adapters/tappx/tappxtest/supplemental/http-err-status.json +++ b/adapters/tappx/tappxtest/supplemental/http-err-status.json @@ -29,7 +29,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, diff --git a/adapters/tappx/tappxtest/supplemental/http-err-status2.json b/adapters/tappx/tappxtest/supplemental/http-err-status2.json index 3d68fdaf7f..cbee18e6e7 100644 --- a/adapters/tappx/tappxtest/supplemental/http-err-status2.json +++ b/adapters/tappx/tappxtest/supplemental/http-err-status2.json @@ -29,7 +29,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.5", + "uri": "http://ssp.api.tappx.com/rtb/v2/ZZ123456PS?tappxkey=pub-12345-android-9876&type_cnn=prebid&v=1.6", "body": { "id": "0000000000001", "test": 1, From d8cdcd69e1f813708008a28fdc0d27cb6387214c Mon Sep 17 00:00:00 2001 From: Anna Yablonsky Date: Mon, 28 Jul 2025 21:28:40 +0300 Subject: [PATCH 035/272] New Adapter: progx - Vidazoo alias (#4428) --- static/bidder-info/progx.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/progx.yaml diff --git a/static/bidder-info/progx.yaml b/static/bidder-info/progx.yaml new file mode 100644 index 0000000000..0e203e8e46 --- /dev/null +++ b/static/bidder-info/progx.yaml @@ -0,0 +1,9 @@ +aliasOf: "vidazoo" +endpoint: "https://exchange.programmaticx.ai/openrtb/" +maintainer: + email: "pxteam@programmaticx.ai" +gvlVendorID: 1344 +userSync: + iframe: + url: https://sync.programmaticx.ai/api/user/html/685297194d85991a5e6e36dd?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} \ No newline at end of file From b15dfc2619302b83ceeab0f4dbffefe18a1fdcba Mon Sep 17 00:00:00 2001 From: "Adserver.Online" <61009237+adserver-online@users.noreply.github.com> Date: Mon, 28 Jul 2025 21:39:22 +0300 Subject: [PATCH 036/272] New Adapter: Kuantyx - Aso alias (#4420) --- static/bidder-info/kuantyx.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 static/bidder-info/kuantyx.yaml diff --git a/static/bidder-info/kuantyx.yaml b/static/bidder-info/kuantyx.yaml new file mode 100644 index 0000000000..b4a2402450 --- /dev/null +++ b/static/bidder-info/kuantyx.yaml @@ -0,0 +1,10 @@ +aliasOf: aso +endpoint: "https://srv.kntxy.com/pbs/bidder?zid={{.ZoneID}}" +maintainer: + email: "ssp@kuantyx.com" +userSync: + # Kuantyx supports user syncing, but requires configuration by the host.Contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - redirect + - iframe From 649aff0ceb7cc03dc11ab973a1251ef74ab193d7 Mon Sep 17 00:00:00 2001 From: inna Date: Mon, 28 Jul 2025 21:53:32 +0300 Subject: [PATCH 037/272] MinuteMedia: Add test endpoint (#4425) --- adapters/minutemedia/minutemedia.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/adapters/minutemedia/minutemedia.go b/adapters/minutemedia/minutemedia.go index 37bb914831..f5a212501a 100644 --- a/adapters/minutemedia/minutemedia.go +++ b/adapters/minutemedia/minutemedia.go @@ -19,12 +19,18 @@ import ( // adapter is a MinuteMedia implementation of the adapters.Bidder interface. type adapter struct { - endpointURL string + endpointURL string + testEndpointURL string } +const ( + testEndpoint = "https://pbs.minutemedia-prebid.com/pbs-test" +) + func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) { return &adapter{ - endpointURL: config.Endpoint, + endpointURL: config.Endpoint, + testEndpointURL: testEndpoint, }, nil } @@ -43,9 +49,14 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, _ *adapters. headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") + endpoint := a.endpointURL + if openRTBRequest.Test == 1 { + endpoint = a.testEndpointURL + } + return append(requestsToBidder, &adapters.RequestData{ Method: http.MethodPost, - Uri: a.endpointURL + "?publisher_id=" + url.QueryEscape(org), + Uri: endpoint + "?publisher_id=" + url.QueryEscape(org), Body: openRTBRequestJSON, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), From be36172c4931c1662f7adaefce42d4f23d6b2150 Mon Sep 17 00:00:00 2001 From: GodefroiRoussel Date: Mon, 28 Jul 2025 21:53:54 +0200 Subject: [PATCH 038/272] Adagio: Add site bidder param and web inventory tests (#4403) Co-authored-by: Godefroi Roussel --- .../adagiotest/exemplary/banner-web.json | 157 ++++++++++++ .../exemplary/multi-formats-app.json | 4 +- .../exemplary/multi-formats-web.json | 183 ++++++++++++++ .../adagiotest/exemplary/multi-imps-app.json | 8 +- .../adagiotest/exemplary/multi-imps-web.json | 220 ++++++++++++++++ .../adagiotest/exemplary/native-web.json | 157 ++++++++++++ .../exemplary/request-with-rtd-module.json | 235 ++++++++++++++++++ .../adagiotest/exemplary/video-web.json | 167 +++++++++++++ adapters/adagio/params_test.go | 7 + openrtb_ext/imp_adagio.go | 1 + static/bidder-info/adagio.yaml | 10 +- static/bidder-params/adagio.json | 5 + 12 files changed, 1145 insertions(+), 9 deletions(-) create mode 100644 adapters/adagio/adagiotest/exemplary/banner-web.json create mode 100644 adapters/adagio/adagiotest/exemplary/multi-formats-web.json create mode 100644 adapters/adagio/adagiotest/exemplary/multi-imps-web.json create mode 100644 adapters/adagio/adagiotest/exemplary/native-web.json create mode 100644 adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json create mode 100644 adapters/adagio/adagiotest/exemplary/video-web.json diff --git a/adapters/adagio/adagiotest/exemplary/banner-web.json b/adapters/adagio/adagiotest/exemplary/banner-web.json new file mode 100644 index 0000000000..51d344c526 --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/banner-web.json @@ -0,0 +1,157 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "type": "banner", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "mtype": 1 + }, + "seat": "adagio", + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/adagiotest/exemplary/multi-formats-app.json b/adapters/adagio/adagiotest/exemplary/multi-formats-app.json index d10985bbae..ee0bfb428d 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-formats-app.json +++ b/adapters/adagio/adagiotest/exemplary/multi-formats-app.json @@ -53,7 +53,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement", "pagetype": "some-pagetype", "category": "some-category" @@ -135,7 +135,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement", "pagetype": "some-pagetype", "category": "some-category" diff --git a/adapters/adagio/adagiotest/exemplary/multi-formats-web.json b/adapters/adagio/adagiotest/exemplary/multi-formats-web.json new file mode 100644 index 0000000000..c62ca197a2 --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/multi-formats-web.json @@ -0,0 +1,183 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "type": "banner", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + }, + "seat": "adagio", + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/adagiotest/exemplary/multi-imps-app.json b/adapters/adagio/adagiotest/exemplary/multi-imps-app.json index 69e38dce1a..bbae86b26f 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-imps-app.json +++ b/adapters/adagio/adagiotest/exemplary/multi-imps-app.json @@ -40,7 +40,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement", "pagetype": "some-pagetype", "category": "some-category" @@ -55,7 +55,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement2", "pagetype": "some-pagetype", "category": "some-category" @@ -124,7 +124,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement", "pagetype": "some-pagetype", "category": "some-category" @@ -139,7 +139,7 @@ }, "ext": { "bidder": { - "organizationId": "1002", + "organizationId": "1000", "placement": "some-placement2", "pagetype": "some-pagetype", "category": "some-category" diff --git a/adapters/adagio/adagiotest/exemplary/multi-imps-web.json b/adapters/adagio/adagiotest/exemplary/multi-imps-web.json new file mode 100644 index 0000000000..619c14bd41 --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/multi-imps-web.json @@ -0,0 +1,220 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + }, + { + "id": "some-impression-id2", + "banner": { + "w": 640, + "h": 100 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement2", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + }, + { + "id": "some-impression-id2", + "banner": { + "w": 640, + "h": 100 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement2", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "impIDs": [ + "some-impression-id", + "some-impression-id2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + }, + { + "id": "b3ae1b4e2fc24a4fb45540082e98e162", + "impid": "some-impression-id2", + "price": 3.0, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 640, + "h": 100, + "mtype": 1 + } + ], + "type": "banner", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + }, + "seat": "adagio", + "type": "banner" + }, + { + "bid": { + "id": "b3ae1b4e2fc24a4fb45540082e98e162", + "impid": "some-impression-id2", + "price": 3.0, + "adm": "some-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 640, + "h": 100, + "mtype": 1 + }, + "seat": "adagio", + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/adagiotest/exemplary/native-web.json b/adapters/adagio/adagiotest/exemplary/native-web.json new file mode 100644 index 0000000000..29a0a77eb2 --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/native-web.json @@ -0,0 +1,157 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 4 + } + ], + "type": "native", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "mtype": 4 + }, + "seat": "adagio", + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json b/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json new file mode 100644 index 0000000000..df8bd286f5 --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json @@ -0,0 +1,235 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "domain": "test.com", + "page": "test.com/some-page.html", + "publisher": { + "id": "123456789", + "domain": "test.com" + }, + "ext": { + "data": { + "pagetype": "my-pagetype-from-ortb2-site-ext-data", + "category": "my-category-from-ortb2-site-ext-data", + "adg_rtd": { + "uid": "some-uid", + "pageviewId": "some-pageviewId", + "features": { + "page_dimensions": "1512x371", + "viewport_dimensions": "1512x371", + "user_timestamp": "1742463886", + "dom_loading": "23" + }, + "session": { + "rnd": 0.9089453747025482, + "pages": 4, + "new": false, + "vwSmplg": 0.1, + "vwSmplgNxt": 0.1, + "expiry": 1742462010772, + "lastActivityTime": 1742460286113, + "id": "some-id", + "testName": "some-name", + "testVersion": "some-version" + } + } + } + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "secure": 1, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + }, + "data": { + "divId": "divId-from-ortb2Imp-ext-data", + "placement": "my-placement-from-ortb2Imp-ext-data", + "adg_rtd": { + "adunit_position": "8x138" + } + }, + "gpid": "gpid#123" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "domain": "test.com", + "page": "test.com/some-page.html", + "publisher": { + "id": "123456789", + "domain": "test.com" + }, + "ext": { + "data": { + "pagetype": "my-pagetype-from-ortb2-site-ext-data", + "category": "my-category-from-ortb2-site-ext-data", + "adg_rtd": { + "uid": "some-uid", + "pageviewId": "some-pageviewId", + "features": { + "page_dimensions": "1512x371", + "viewport_dimensions": "1512x371", + "user_timestamp": "1742463886", + "dom_loading": "23" + }, + "session": { + "rnd": 0.9089453747025482, + "pages": 4, + "new": false, + "vwSmplg": 0.1, + "vwSmplgNxt": 0.1, + "expiry": 1742462010772, + "lastActivityTime": 1742460286113, + "id": "some-id", + "testName": "some-name", + "testVersion": "some-version" + } + } + } + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "secure": 1, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + }, + "data": { + "divId": "divId-from-ortb2Imp-ext-data", + "placement": "my-placement-from-ortb2Imp-ext-data", + "adg_rtd": { + "adunit_position": "8x138" + } + }, + "gpid": "gpid#123" + } + } + ] + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "type": "banner", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "mtype": 1 + }, + "seat": "adagio", + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/adagiotest/exemplary/video-web.json b/adapters/adagio/adagiotest/exemplary/video-web.json new file mode 100644 index 0000000000..89189e359b --- /dev/null +++ b/adapters/adagio/adagiotest/exemplary/video-web.json @@ -0,0 +1,167 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "https://mp-ams.4dex.io/pbserver", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "source": { + "tid": "some-tid" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "organizationId": "1000", + "placement": "some-placement", + "site": "test-com", + "pagetype": "some-pagetype", + "category": "some-category" + } + } + } + ] + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 2 + } + ], + "type": "video", + "seat": "adagio" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "adagio": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "mtype": 2 + }, + "seat": "adagio", + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adagio/params_test.go b/adapters/adagio/params_test.go index adc83a60fe..c0c09a2734 100644 --- a/adapters/adagio/params_test.go +++ b/adapters/adagio/params_test.go @@ -35,9 +35,13 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"organizationId":"1000","placement":"some-placement"}`, + `{"organizationId":"1000","placement":"some-placement","site":"mywebsite-com"}`, `{"organizationId":"1000","placement":"some-placement","pagetype":"some-pagetype"}`, `{"organizationId":"1000","placement":"some-placement","category":"some-category"}`, + `{"organizationId":"1000","placement":"some-placement","pagetype":"some-pagetype","site":"mywebsite-com"}`, + `{"organizationId":"1000","placement":"some-placement","category":"some-category","site":"mywebsite-com"}`, `{"organizationId":"1000","placement":"some-placement","pagetype":"some-pagetype","category":"some-category"}`, + `{"organizationId":"1000","placement":"some-placement","pagetype":"some-pagetype","category":"some-category","site":"mywebsite-com"}`, } var invalidParams = []string{ @@ -52,6 +56,7 @@ var invalidParams = []string{ `{"placement":"some-placement"}`, `{"category":"some-category"}`, `{"pagetype":"some-pagetype"}`, + `{"site":"mywebsite-com"}`, `{"organizationId":1000}`, `{"organizationId":1000,"placement":"some-placement"}`, `{"organizationId":"1000","placement":"this-is-a-very-very-long-placement"}`, @@ -60,4 +65,6 @@ var invalidParams = []string{ `{"organizationId":"1000","placement":"some-placement","pagetype":"this-is-a-very-very-long-pagetype"}`, `{"organizationId":"1000","placement":"some-placement","category":123456}`, `{"organizationId":"1000","placement":"some-placement","category":"this-is-a-very-very-long-category"}`, + `{"organizationId":"1000","placement":"some-placement","site":123456}`, + `{"organizationId":"1000","placement":"some-placement","site":"this-is-a-very-very-very-very-very-very-long-site-name"}`, } diff --git a/openrtb_ext/imp_adagio.go b/openrtb_ext/imp_adagio.go index 9c8eda8141..ced2cea742 100644 --- a/openrtb_ext/imp_adagio.go +++ b/openrtb_ext/imp_adagio.go @@ -3,6 +3,7 @@ package openrtb_ext type ExtImpAdagio struct { OrganizationID string `json:"organizationId"` Placement string `json:"placement"` + Site string `json:"site,omitempty"` Pagetype string `json:"pagetype,omitempty"` Category string `json:"category,omitempty"` } diff --git a/static/bidder-info/adagio.yaml b/static/bidder-info/adagio.yaml index 4e9933155b..3d616d0b5a 100644 --- a/static/bidder-info/adagio.yaml +++ b/static/bidder-info/adagio.yaml @@ -1,10 +1,14 @@ # Please deploy this config in each of your datacenters with the appropriate regional subdomain. # Replace the `REGION` by one of the value below: -# - For AMER: las => (https://mp-las.4dex.io/pbserver) -# - For EMEA: ams => (https://mp-ams.4dex.io/pbserver) -# - For APAC: tyo => (https://mp-tyo.4dex.io/pbserver) +# - For AMER: las => (https://mp-las.4dex.io/pbserver and https://u-las.4dex.io/pbserver/usync.html) +# - For EMEA: ams => (https://mp-ams.4dex.io/pbserver and https://u-amx.4dex.io/pbserver/usync.html) +# - For APAC: tyo => (https://mp-tyo.4dex.io/pbserver and https://u-tyo.4dex.io/pbserver/usync.html) # And set disabled to `false`. endpoint: "https://mp-REGION.4dex.io/pbserver" +userSync: + iframe: + url: "https://u-REGION.4dex.io/pbserver/usync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" disabled: true endpointCompression: gzip diff --git a/static/bidder-params/adagio.json b/static/bidder-params/adagio.json index 2a4fdbc5c1..4be32a3592 100644 --- a/static/bidder-params/adagio.json +++ b/static/bidder-params/adagio.json @@ -13,6 +13,11 @@ "description": "Refers to the placement of an adunit in a page. Must not contain any information about the type of device.", "maxLength": 30 }, + "site": { + "type": "string", + "description": "Name of the site. Handed out by Adagio.", + "maxLength": 50 + }, "pagetype": { "type": "string", "description": "Describes what kind of content will be present in the page.", From a9dfd9a0d440887975965d7d4a5b6d3f9eda23bc Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:10:21 -0700 Subject: [PATCH 039/272] Modularity: Add hook code to module invocation context (#4036) --- hooks/hookexecution/execution.go | 1 + hooks/hookstage/invocation.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go index 7bb86cbb68..182af44dbd 100644 --- a/hooks/hookexecution/execution.go +++ b/hooks/hookexecution/execution.go @@ -73,6 +73,7 @@ func executeGroup[H any, P any]( for _, hook := range group.Hooks { mCtx := executionCtx.getModuleContext(hook.Module) + mCtx.HookImplCode = hook.Code newPayload := handleModuleActivities(hook.Code, executionCtx.activityControl, payload, executionCtx.account) wg.Add(1) go func(hw hooks.HookWrapper[H], moduleCtx hookstage.ModuleInvocationContext) { diff --git a/hooks/hookstage/invocation.go b/hooks/hookstage/invocation.go index 3259f4e970..b5452af7fc 100644 --- a/hooks/hookstage/invocation.go +++ b/hooks/hookstage/invocation.go @@ -29,6 +29,8 @@ type ModuleInvocationContext struct { Endpoint string // ModuleContext holds values that the module passes to itself from the previous stages. ModuleContext ModuleContext + // HookImplCode is the hook_impl_code for a module instance to differentiate between multiple hooks + HookImplCode string } // ModuleContext holds arbitrary data passed between module hooks at different stages. From 8b1c4cc8e079fdc6e3d3547a962af007091d9ad5 Mon Sep 17 00:00:00 2001 From: Anton Babak <76536883+AntoxaAntoxic@users.noreply.github.com> Date: Mon, 28 Jul 2025 22:20:52 +0200 Subject: [PATCH 040/272] Rubicon: Pass ext.prebid.multibid[].maxbids to XAPI (#4412) --- adapters/rubicon/rubicon.go | 40 +++++++++++++++---- .../rubicontest/exemplary/simple-banner.json | 15 ++++++- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go index 2a433464eb..b0a694905a 100644 --- a/adapters/rubicon/rubicon.go +++ b/adapters/rubicon/rubicon.go @@ -56,7 +56,8 @@ type bidRequestExt struct { } type bidRequestExtPrebid struct { - Bidders bidRequestExtPrebidBidders `json:"bidders"` + Bidders bidRequestExtPrebidBidders `json:"bidders"` + MultiBid []*openrtb_ext.ExtMultiBid `json:"multibid,omitempty"` } type bidRequestExtPrebidBidders struct { @@ -77,10 +78,11 @@ type rubiconImpExtRPTrack struct { } type rubiconImpExt struct { - RP rubiconImpExtRP `json:"rp,omitempty"` - GPID string `json:"gpid,omitempty"` - Skadn json.RawMessage `json:"skadn,omitempty"` - Tid string `json:"tid,omitempty"` + RP rubiconImpExtRP `json:"rp,omitempty"` + GPID string `json:"gpid,omitempty"` + Skadn json.RawMessage `json:"skadn,omitempty"` + Tid string `json:"tid,omitempty"` + MaxBids *int `json:"maxbids,omitempty"` } type rubiconImpExtRP struct { @@ -241,6 +243,8 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada impsToExtNotGrouped, errs := createImpsToExtMap(request.Imp) impsToExtMap := prepareImpsToExtMap(impsToExtNotGrouped) + maxBids := getMaxBids(request) + rubiconRequest := *request for imp, bidderExt := range impsToExtMap { rubiconExt := bidderExt.Bidder @@ -268,9 +272,10 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada Target: target, Track: rubiconImpExtRPTrack{Mint: "", MintVersion: ""}, }, - GPID: bidderExt.Gpid, - Skadn: bidderExt.Skadn, - Tid: bidderExt.Tid, + GPID: bidderExt.Gpid, + Skadn: bidderExt.Skadn, + Tid: bidderExt.Tid, + MaxBids: maxBids, } imp.Ext, err = json.Marshal(&impExt) @@ -525,6 +530,25 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada return requestData, errs } +func getMaxBids(bidRequest *openrtb2.BidRequest) *int { + var bidRequestExt bidRequestExt + if err := jsonutil.Unmarshal(bidRequest.Ext, &bidRequestExt); err != nil { + return nil + } + + if len(bidRequestExt.Prebid.MultiBid) == 0 { + return nil + } + + multiBid := bidRequestExt.Prebid.MultiBid[0] + + if multiBid == nil { + return nil + } + + return multiBid.MaxBids +} + func createImpsToExtMap(imps []openrtb2.Imp) (map[*openrtb2.Imp]rubiconExtImpBidder, []error) { impsToExtMap := make(map[*openrtb2.Imp]rubiconExtImpBidder) errs := make([]error, 0) diff --git a/adapters/rubicon/rubicontest/exemplary/simple-banner.json b/adapters/rubicon/rubicontest/exemplary/simple-banner.json index 7a34db5e8d..b422f08ad5 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-banner.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-banner.json @@ -148,7 +148,17 @@ } } } - ] + ], + "ext": { + "prebid": { + "multibid": [ + { + "bidder": "rubicon", + "maxbids": 2 + } + ] + } + } }, "httpCalls": [ { @@ -338,7 +348,8 @@ }, "sourceapp": "000", "version": "1.0" - } + }, + "maxbids": 2 } } ] From a514d261cac80cbe52d3b308a6a3288480887921 Mon Sep 17 00:00:00 2001 From: Kacper Fus Date: Mon, 28 Jul 2025 22:29:21 +0200 Subject: [PATCH 041/272] OpenX: Add gpp params to user sync (#4445) Co-authored-by: gmiedlar-ox --- static/bidder-info/openx.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/openx.yaml b/static/bidder-info/openx.yaml index 8678a65492..12612046b0 100644 --- a/static/bidder-info/openx.yaml +++ b/static/bidder-info/openx.yaml @@ -17,11 +17,12 @@ capabilities: modifyingVastXmlAllowed: true userSync: iframe: - url: "https://u.openx.net/w/1.0/cm?id=891039ac-a916-42bb-a651-4be9e3b201da&ph=a3aece0c-9e80-4316-8deb-faf804779bd1&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r={{.RedirectURL}}" + url: "https://u.openx.net/w/1.0/cm?id=891039ac-a916-42bb-a651-4be9e3b201da&ph=a3aece0c-9e80-4316-8deb-faf804779bd1&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" userMacro: "{OPENX_ID}" redirect: - url: "https://rtb.openx.net/sync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r={{.RedirectURL}}" + url: "https://rtb.openx.net/sync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" userMacro: "${UID}" openrtb: version: 2.6 + gpp-supported: true From e5570892b3c7e32a210149ab670dbaa7d21d0517 Mon Sep 17 00:00:00 2001 From: tomaskoutny-blis <60094686+tomaskoutny-blis@users.noreply.github.com> Date: Tue, 29 Jul 2025 17:21:56 +0200 Subject: [PATCH 042/272] New Adapter: Blis (#4304) Co-authored-by: Tomas Koutny --- adapters/blis/blis.go | 135 ++++++++++++++ adapters/blis/blis_test.go | 29 +++ adapters/blis/blistest/exemplary/banner.json | 171 ++++++++++++++++++ adapters/blis/blistest/exemplary/native.json | 129 +++++++++++++ adapters/blis/blistest/exemplary/video.json | 153 ++++++++++++++++ .../supplemental/invalid-imp-ext-bidder.json | 18 ++ .../supplemental/invalid-imp-ext.json | 17 ++ .../supplemental/response-http-204.json | 54 ++++++ .../supplemental/response-http-500.json | 58 ++++++ .../supplemental/unsupported-media-type.json | 84 +++++++++ adapters/blis/params_test.go | 61 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_blis.go | 5 + static/bidder-info/blis.yaml | 25 +++ static/bidder-params/blis.json | 16 ++ 16 files changed, 959 insertions(+) create mode 100644 adapters/blis/blis.go create mode 100644 adapters/blis/blis_test.go create mode 100644 adapters/blis/blistest/exemplary/banner.json create mode 100644 adapters/blis/blistest/exemplary/native.json create mode 100644 adapters/blis/blistest/exemplary/video.json create mode 100644 adapters/blis/blistest/supplemental/invalid-imp-ext-bidder.json create mode 100644 adapters/blis/blistest/supplemental/invalid-imp-ext.json create mode 100644 adapters/blis/blistest/supplemental/response-http-204.json create mode 100644 adapters/blis/blistest/supplemental/response-http-500.json create mode 100644 adapters/blis/blistest/supplemental/unsupported-media-type.json create mode 100644 adapters/blis/params_test.go create mode 100644 openrtb_ext/imp_blis.go create mode 100644 static/bidder-info/blis.yaml create mode 100644 static/bidder-params/blis.json diff --git a/adapters/blis/blis.go b/adapters/blis/blis.go new file mode 100644 index 0000000000..ed701a2241 --- /dev/null +++ b/adapters/blis/blis.go @@ -0,0 +1,135 @@ +package blis + +import ( + "fmt" + "net/http" + "strconv" + "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/iterutil" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpointTemplate *template.Template +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %w", err) + } + + bidder := &adapter{ + endpointTemplate: endpointTemplate, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var impExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[0].Ext, &impExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Infomation: %v", 0, err), + }} + } + var impExtBidder openrtb_ext.ImpExtBlis + if err := jsonutil.Unmarshal(impExt.Bidder, &impExtBidder); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext.bidder for impression index %d. Error Infomation: %v", 0, err), + }} + } + + endpoint, err := a.buildEndpointURL(&impExtBidder) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("X-Supply-Partner-Id", impExtBidder.SupplyPartnerID) + + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: endpoint, + Headers: headers, + Body: requestJSON, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) buildEndpointURL(impExtBidder *openrtb_ext.ImpExtBlis) (string, error) { + endpointParams := macros.EndpointTemplateParams{SupplyId: impExtBidder.SupplyPartnerID} + return macros.ResolveMacros(a.endpointTemplate, endpointParams) +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + var errors []error + for seatBid := range iterutil.SlicePointerValues(response.SeatBid) { + for bid := range iterutil.SlicePointerValues(seatBid.Bid) { + resolveMacros(bid) + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + return bidResponse, nil +} + +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 + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse media type of impression ID \"%s\"", bid.ImpID), + } + } +} + +func resolveMacros(bid *openrtb2.Bid) { + if bid != nil { + price := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.NURL = strings.ReplaceAll(bid.NURL, "${AUCTION_PRICE}", price) + bid.AdM = strings.ReplaceAll(bid.AdM, "${AUCTION_PRICE}", price) + bid.BURL = strings.ReplaceAll(bid.BURL, "${AUCTION_PRICE}", price) + } +} diff --git a/adapters/blis/blis_test.go b/adapters/blis/blis_test.go new file mode 100644 index 0000000000..b9fcc9836a --- /dev/null +++ b/adapters/blis/blis_test.go @@ -0,0 +1,29 @@ +package blis + +import ( + "github.com/stretchr/testify/assert" + "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/stretchr/testify/require" +) + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderBlis, config.Adapter{ + Endpoint: "{{Malformed}}"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBlis, config.Adapter{ + Endpoint: "https://example.endpoint/{{.SupplyId}}"}, + config.Server{ExternalUrl: "http://example.server", GvlID: 1, DataCenter: "2"}) + + require.NoError(t, buildErr) + + adapterstest.RunJSONBidderTest(t, "blistest", bidder) +} diff --git a/adapters/blis/blistest/exemplary/banner.json b/adapters/blis/blistest/exemplary/banner.json new file mode 100644 index 0000000000..e793e8dd17 --- /dev/null +++ b/adapters/blis/blistest/exemplary/banner.json @@ -0,0 +1,171 @@ +{ + "mockBidRequest": { + "id": "123456789", + "imp": [ + { + "ext": { + "bidder": { + "spid": "999" + } + }, + "id": "testimp", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + }, + { + "w": 728, + "h": 90 + } + ] + }, + "bidfloor": 0.98, + "bidfloorcur": "USD" + } + ], + "cur": [ + "USD" + ], + "site": { + "publisher": { + "domain": "example.com" + }, + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "cat": [ + "site-cat" + ] + }, + "device": { + "w": 1434, + "h": 686, + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "headers": { + "X-Supply-Partner-Id": [ + "999" + ] + }, + "impIDs": [ + "testimp" + ], + "body": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + }, + { + "w": 728, + "h": 90 + } + ] + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "spid": "999" + } + } + } + ], + "site": { + "cat": [ + "site-cat" + ], + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "publisher": { + "domain": "example.com" + } + }, + "device": { + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8", + "h": 686, + "w": 1434 + }, + "cur": [ + "USD" + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123456789", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.2, + "crid": "9999999", + "w": 320, + "h": 50, + "adomain": [ + "example.com" + ], + "cid": "999999", + "iurl": "https://adserverexample.com/example.gif", + "adm": "\"\"", + "cat": [ + "IAB3-1" + ], + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "1", + "impid": "testimp", + "price": 1.2, + "crid": "9999999", + "w": 320, + "h": 50, + "adomain": [ + "example.com" + ], + "cid": "999999", + "iurl": "https://adserverexample.com/example.gif", + "adm": "\"\"", + "cat": [ + "IAB3-1" + ], + "burl": "https://trackingexample.com/pixel?wp=1.2", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/blis/blistest/exemplary/native.json b/adapters/blis/blistest/exemplary/native.json new file mode 100644 index 0000000000..b49914d9db --- /dev/null +++ b/adapters/blis/blistest/exemplary/native.json @@ -0,0 +1,129 @@ +{ + "mockBidRequest": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}},{\"id\":3,\"data\":{\"type\":2}}]}", + "ver": "1.2" + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "spid": "999" + } + } + } + ], + "cur": ["USD"], + "site": { + "publisher": { + "domain": "example.com" + }, + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "cat": ["site-cat"] + }, + "device": { + "w": 1434, + "h": 686, + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "headers": { + "X-Supply-Partner-Id": ["999"] + }, + "impIDs": ["testimp"], + "body": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}},{\"id\":3,\"data\":{\"type\":2}}]}", + "ver": "1.2" + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "spid": "999" + } + } + } + ], + "site": { + "cat": ["site-cat"], + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "publisher": { + "domain": "example.com" + } + }, + "device": { + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8", + "h": 686, + "w": 1434 + }, + "cur": ["USD"] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123456789", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.3, + "crid": "9999999", + "adomain": ["example.com"], + "cid": "999999", + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Native Ad Title\"}},{\"id\":2,\"img\":{\"url\":\"https://adserverexample.com/image.jpg\",\"w\":1200,\"h\":627}},{\"id\":3,\"data\":{\"value\":\"Sponsored\"}}],\"link\":{\"url\":\"https://clickexample.com\"},\"imptrackers\":[\"https://trackingexample.com/pixel?wp=${AUCTION_PRICE}\"]}}", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 4 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "1", + "impid": "testimp", + "price": 1.3, + "crid": "9999999", + "adomain": ["example.com"], + "cid": "999999", + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Native Ad Title\"}},{\"id\":2,\"img\":{\"url\":\"https://adserverexample.com/image.jpg\",\"w\":1200,\"h\":627}},{\"id\":3,\"data\":{\"value\":\"Sponsored\"}}],\"link\":{\"url\":\"https://clickexample.com\"},\"imptrackers\":[\"https://trackingexample.com/pixel?wp=1.3\"]}}", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=1.3", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/blis/blistest/exemplary/video.json b/adapters/blis/blistest/exemplary/video.json new file mode 100644 index 0000000000..3eb743e1e7 --- /dev/null +++ b/adapters/blis/blistest/exemplary/video.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "123456789", + "imp": [ + { + "ext": { + "bidder": { + "spid": "999" + } + }, + "id": "testimp", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "bidfloor": 0.98, + "bidfloorcur": "USD" + } + ], + "cur": [ + "USD" + ], + "site": { + "publisher": { + "domain": "example.com" + }, + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "cat": [ + "site-cat" + ] + }, + "device": { + "w": 1434, + "h": 686, + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "headers": { + "X-Supply-Partner-Id": [ + "999" + ] + }, + "impIDs": [ + "testimp" + ], + "body": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "spid": "999" + } + } + } + ], + "site": { + "cat": [ + "site-cat" + ], + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "publisher": { + "domain": "example.com" + } + }, + "device": { + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8", + "h": 686, + "w": 1434 + }, + "cur": [ + "USD" + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123456789", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.5, + "crid": "9999999", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "cid": "999999", + "adm": "blistracker", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "1", + "impid": "testimp", + "price": 1.5, + "crid": "9999999", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "cid": "999999", + "adm": "blistracker", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=1.5", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/blis/blistest/supplemental/invalid-imp-ext-bidder.json b/adapters/blis/blistest/supplemental/invalid-imp-ext-bidder.json new file mode 100644 index 0000000000..2d0e1a270c --- /dev/null +++ b/adapters/blis/blistest/supplemental/invalid-imp-ext-bidder.json @@ -0,0 +1,18 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "ext": {} + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext.bidder for impression", + "comparison": "startswith" + } + ] +} \ No newline at end of file diff --git a/adapters/blis/blistest/supplemental/invalid-imp-ext.json b/adapters/blis/blistest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..31e261e6fa --- /dev/null +++ b/adapters/blis/blistest/supplemental/invalid-imp-ext.json @@ -0,0 +1,17 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp" + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext for impression", + "comparison": "startswith" + } + ] +} \ No newline at end of file diff --git a/adapters/blis/blistest/supplemental/response-http-204.json b/adapters/blis/blistest/supplemental/response-http-204.json new file mode 100644 index 0000000000..2803abe994 --- /dev/null +++ b/adapters/blis/blistest/supplemental/response-http-204.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ] +} \ No newline at end of file diff --git a/adapters/blis/blistest/supplemental/response-http-500.json b/adapters/blis/blistest/supplemental/response-http-500.json new file mode 100644 index 0000000000..14f878d5f5 --- /dev/null +++ b/adapters/blis/blistest/supplemental/response-http-500.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code", + "comparison": "startswith" + }] +} \ No newline at end of file diff --git a/adapters/blis/blistest/supplemental/unsupported-media-type.json b/adapters/blis/blistest/supplemental/unsupported-media-type.json new file mode 100644 index 0000000000..4a6a40f6a2 --- /dev/null +++ b/adapters/blis/blistest/supplemental/unsupported-media-type.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/999", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "spid": "999" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.2, + "crid": "9999999", + "w": 320, + "h": 50, + "adomain": [ + "example.com" + ], + "cid": "999999", + "adm": "\"\"", + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 6 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + ] + } + ] +} \ No newline at end of file diff --git a/adapters/blis/params_test.go b/adapters/blis/params_test.go new file mode 100644 index 0000000000..2a62836a06 --- /dev/null +++ b/adapters/blis/params_test.go @@ -0,0 +1,61 @@ +package blis + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type testSpec struct { + name string + json string + wantErr bool +} + +func testParams(t *testing.T, specs []testSpec) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema") + + for _, spec := range specs { + t.Run(spec.name, func(t *testing.T) { + err := validator.Validate(openrtb_ext.BidderBlis, json.RawMessage(spec.json)) + if spec.wantErr { + assert.Error(t, err, "Expected error but got none for: %s", spec.json) + } else { + assert.NoError(t, err, "Unexpected error for: %s", spec.json) + } + }) + } +} + +func TestValidParams(t *testing.T) { + testParams(t, []testSpec{ + { + name: "Valid params with spid", + json: `{"spid": "9999"}`, + }, + }) +} + +func TestInvalidParams(t *testing.T) { + testParams(t, []testSpec{ + { + name: "Empty params", + json: `{}`, + wantErr: true, + }, + { + name: "Empty spid", + json: `{"spid": ""}`, + wantErr: true, + }, + { + name: "Invalid spid type", + json: `{"spid": 9999}`, + wantErr: true, + }, + }) +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index f7920a7e7c..28303f1323 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -65,6 +65,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/bigoad" "github.com/prebid/prebid-server/v3/adapters/blasto" "github.com/prebid/prebid-server/v3/adapters/bliink" + "github.com/prebid/prebid-server/v3/adapters/blis" "github.com/prebid/prebid-server/v3/adapters/blue" "github.com/prebid/prebid-server/v3/adapters/bluesea" "github.com/prebid/prebid-server/v3/adapters/bmtm" @@ -325,6 +326,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBigoAd: bigoad.Builder, openrtb_ext.BidderBlasto: blasto.Builder, openrtb_ext.BidderBliink: bliink.Builder, + openrtb_ext.BidderBlis: blis.Builder, openrtb_ext.BidderBlue: blue.Builder, openrtb_ext.BidderBluesea: bluesea.Builder, openrtb_ext.BidderBmtm: bmtm.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index be86afd66a..0e33944265 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -81,6 +81,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderBigoAd, BidderBlasto, BidderBliink, + BidderBlis, BidderBlue, BidderBluesea, BidderBmtm, @@ -448,6 +449,7 @@ const ( BidderBigoAd BidderName = "bigoad" BidderBlasto BidderName = "blasto" BidderBliink BidderName = "bliink" + BidderBlis BidderName = "blis" BidderBlue BidderName = "blue" BidderBluesea BidderName = "bluesea" BidderBmtm BidderName = "bmtm" diff --git a/openrtb_ext/imp_blis.go b/openrtb_ext/imp_blis.go new file mode 100644 index 0000000000..937ed22f2b --- /dev/null +++ b/openrtb_ext/imp_blis.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtBlis struct { + SupplyPartnerID string `json:"spid"` +} diff --git a/static/bidder-info/blis.yaml b/static/bidder-info/blis.yaml new file mode 100644 index 0000000000..0c8164f547 --- /dev/null +++ b/static/bidder-info/blis.yaml @@ -0,0 +1,25 @@ +endpoint: "https://prebid.lb.infinity.blismedia.com/rtb/213/{{.SupplyId}}" +endpointCompression: gzip +geoscope: + - global +maintainer: + email: prebid-support@blis.com +gvlVendorID: 94 +modifyingVastXmlAllowed: true +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://tr.blismedia.com/v1/api/sync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}" + userMacro: "%%BLIS_USER_TOKEN%%" \ No newline at end of file diff --git a/static/bidder-params/blis.json b/static/bidder-params/blis.json new file mode 100644 index 0000000000..df8c7aeddb --- /dev/null +++ b/static/bidder-params/blis.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Blis Adapter Params", + "description": "A schema which validates params accepted by the Blis adapter", + "type": "object", + + "properties": { + "spid": { + "type": "string", + "minLength": 1, + "description": "Unique supply partner ID provided by Blis" + } + }, + + "required": ["spid"] +} From 97489f7b9430d21354a4ddfb664ee0f867680106 Mon Sep 17 00:00:00 2001 From: Vincent Bachelier Date: Tue, 29 Jul 2025 22:58:51 +0200 Subject: [PATCH 043/272] Ogury: Support gpp for cookie sync (#4406) --- static/bidder-info/ogury.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/static/bidder-info/ogury.yaml b/static/bidder-info/ogury.yaml index a64a874a52..233cc7e316 100644 --- a/static/bidder-info/ogury.yaml +++ b/static/bidder-info/ogury.yaml @@ -15,5 +15,8 @@ capabilities: - banner userSync: iframe: - url: "https://ms-cookie-sync.presage.io/user-sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&source=prebids2s" + url: "https://ms-cookie-sync.presage.io/user-sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&source=prebids2s" + userMacro: "{{OGURY_UID}}" + redirect: + url: "https://ms-cookie-sync.presage.io/user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&partner=prebids2s" userMacro: "{{OGURY_UID}}" From bd00ef2706acce9e8940bd1d55dc990222e6ec87 Mon Sep 17 00:00:00 2001 From: andre-gielow-ttd <124626380+andre-gielow-ttd@users.noreply.github.com> Date: Wed, 30 Jul 2025 14:41:54 -0400 Subject: [PATCH 044/272] TheTradeDesk: Resolve AUCTION_PRICE macro (#4448) --- adapters/thetradedesk/thetradedesk.go | 12 ++ adapters/thetradedesk/thetradedesk_test.go | 144 ++++++++++++++++++ .../auction-price-macro-replacement.json | 142 +++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go index 2fdf227d15..f22744ffdc 100644 --- a/adapters/thetradedesk/thetradedesk.go +++ b/adapters/thetradedesk/thetradedesk.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "regexp" + "strconv" + "strings" "text/template" "github.com/prebid/prebid-server/v3/adapters" @@ -176,6 +178,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest for _, bid := range seatBid.Bid { bid := bid + resolveAuctionPriceMacros(&bid) bidType, err := getBidType(bid.MType) if err != nil { @@ -232,3 +235,12 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co templateEndpoint: template, }, nil } + +func resolveAuctionPriceMacros(bid *openrtb2.Bid) { + if bid == nil { + return + } + price := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1) + bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) +} diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go index 22fdcebeec..11ffda30d9 100644 --- a/adapters/thetradedesk/thetradedesk_test.go +++ b/adapters/thetradedesk/thetradedesk_test.go @@ -451,3 +451,147 @@ func TestTheTradeDeskAdapter_BuildEndpoint(t *testing.T) { }) } } + +func TestResolveAuctionPriceMacros(t *testing.T) { + tests := []struct { + name string + bid *openrtb2.Bid + expectedNURL string + expectedAdM string + }{ + { + name: "nil_bid", + bid: nil, + }, + { + name: "no_macros", + bid: &openrtb2.Bid{ + Price: 1.23, + NURL: "http://example.com/nurl", + AdM: "
Ad content
", + }, + expectedNURL: "http://example.com/nurl", + expectedAdM: "
Ad content
", + }, + { + name: "macros_in_both_nurl_and_adm", + bid: &openrtb2.Bid{ + Price: 1.50, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Ad content with price ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=1.5", + expectedAdM: "
Ad content with price 1.5
", + }, + { + name: "macro_only_in_nurl", + bid: &openrtb2.Bid{ + Price: 2.75, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Ad content
", + }, + expectedNURL: "http://example.com/nurl?price=2.75", + expectedAdM: "
Ad content
", + }, + { + name: "macro_only_in_adm", + bid: &openrtb2.Bid{ + Price: 0.99, + NURL: "http://example.com/nurl", + AdM: "
Price: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl", + expectedAdM: "
Price: 0.99
", + }, + { + name: "multiple_macros_in_same_field", + bid: &openrtb2.Bid{ + Price: 3.14, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}&backup_price=${AUCTION_PRICE}", + AdM: "
Price: ${AUCTION_PRICE}, Backup: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=3.14&backup_price=3.14", + expectedAdM: "
Price: 3.14, Backup: 3.14
", + }, + { + name: "zero_price", + bid: &openrtb2.Bid{ + Price: 0.0, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Price: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=0", + expectedAdM: "
Price: 0
", + }, + { + name: "very_small_price", + bid: &openrtb2.Bid{ + Price: 0.001, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Price: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=0.001", + expectedAdM: "
Price: 0.001
", + }, + { + name: "large_price", + bid: &openrtb2.Bid{ + Price: 999.999, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Price: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=999.999", + expectedAdM: "
Price: 999.999
", + }, + { + name: "integer_price", + bid: &openrtb2.Bid{ + Price: 5.0, + NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", + AdM: "
Price: ${AUCTION_PRICE}
", + }, + expectedNURL: "http://example.com/nurl?price=5", + expectedAdM: "
Price: 5
", + }, + { + name: "empty_nurl_and_adm", + bid: &openrtb2.Bid{ + Price: 1.23, + NURL: "", + AdM: "", + }, + expectedNURL: "", + expectedAdM: "", + }, + { + name: "case_sensitive_macro_not_replaced", + bid: &openrtb2.Bid{ + Price: 1.50, + NURL: "http://example.com/nurl?price=${auction_price}", + AdM: "
Price: ${Auction_Price}
", + }, + expectedNURL: "http://example.com/nurl?price=${auction_price}", + expectedAdM: "
Price: ${Auction_Price}
", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var testBid *openrtb2.Bid + if tt.bid != nil { + bidCopy := *tt.bid + testBid = &bidCopy + } + + resolveAuctionPriceMacros(testBid) + + if tt.bid == nil { + assert.Nil(t, testBid) + return + } + + assert.Equal(t, tt.expectedNURL, testBid.NURL, "NURL should match expected value") + assert.Equal(t, tt.expectedAdM, testBid.AdM, "AdM should match expected value") + }) + } +} diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json new file mode 100644 index 0000000000..2629242b01 --- /dev/null +++ b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "ttd.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 100, + "h": 150 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://direct.adsrvr.org/bid/bidder/ttd", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "ttd.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 1.50, + "crid": "creative-123", + "adm": "", + "nurl": "http://win-notification.ttd.com?wp=${AUCTION_PRICE}&id=test-slot-id", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 1.50, + "crid": "creative-123", + "adm": "", + "nurl": "http://win-notification.ttd.com?wp=1.5&id=test-slot-id", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file From 21d9bab49d6e5de58d8ce0fff49834e269424543 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Fri, 1 Aug 2025 11:29:40 -0400 Subject: [PATCH 045/272] Fix: Set account http fetcher defaults enabling env vars (#4460) --- config/config.go | 9 +++++++++ config/config_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/config/config.go b/config/config.go index 422af3d440..80cdaa3335 100644 --- a/config/config.go +++ b/config/config.go @@ -1083,7 +1083,16 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("accounts.filesystem.enabled", false) v.SetDefault("accounts.filesystem.directorypath", "./stored_requests/data/by_id") + v.SetDefault("accounts.http.endpoint", "") + v.SetDefault("accounts.http.use_rfc3986_compliant_request_builder", false) v.SetDefault("accounts.in_memory_cache.type", "none") + v.SetDefault("accounts.in_memory_cache.ttl_seconds", 0) + v.SetDefault("accounts.in_memory_cache.size_bytes", 0) + v.SetDefault("accounts.cache_events.enabled", false) + v.SetDefault("accounts.cache_events.endpoint", "") + v.SetDefault("accounts.http_events.endpoint", "") + v.SetDefault("accounts.http_events.refresh_rate_seconds", 0) + v.SetDefault("accounts.http_events.timeout_ms", 0) v.BindEnv("user_sync.external_url") v.BindEnv("user_sync.coop_sync.default") diff --git a/config/config_test.go b/config/config_test.go index d1493afce0..49248e8ed6 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -167,6 +167,18 @@ func TestDefaults(t *testing.T) { cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "accounts.filesystem.enabled", false, cfg.Accounts.Files.Enabled) + cmpStrings(t, "accounts.filesystem.directorypath", "./stored_requests/data/by_id", cfg.Accounts.Files.Path) + cmpStrings(t, "accounts.http.endpoint", "", cfg.Accounts.HTTP.Endpoint) + cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", false, cfg.Accounts.HTTP.UseRfcCompliantBuilder) + cmpStrings(t, "accounts.in_memory_cache.type", "none", cfg.Accounts.InMemoryCache.Type) + cmpInts(t, "accounts.in_memory_cache.ttl_seconds", 0, cfg.Accounts.InMemoryCache.TTL) + cmpInts(t, "accounts.in_memory_cache.size_bytes", 0, cfg.Accounts.InMemoryCache.Size) + cmpBools(t, "accounts.cache_events.enabled", false, cfg.Accounts.CacheEvents.Enabled) + cmpStrings(t, "accounts.cache_events.endpoint", "", cfg.Accounts.CacheEvents.Endpoint) + cmpStrings(t, "accounts.http_events.endpoint", "", cfg.Accounts.HTTPEvents.Endpoint) + cmpInts(t, "accounts.http_events.refresh_rate_seconds", 0, int(cfg.Accounts.HTTPEvents.RefreshRate)) + cmpInts(t, "accounts.http_events.timeout_ms", 0, int(cfg.Accounts.HTTPEvents.Timeout)) cmpBools(t, "auto_gen_source_tid", true, cfg.AutoGenSourceTID) cmpBools(t, "generate_bid_id", false, cfg.GenerateBidID) cmpStrings(t, "experiment.adscert.mode", "off", cfg.Experiment.AdCerts.Mode) @@ -350,6 +362,24 @@ func TestDefaults(t *testing.T) { // When adding a new field, make sure the indentations are spaces not tabs otherwise read config may fail to parse the new field value. var fullConfig = []byte(` +accounts: + filesystem: + enabled: true + directorypath: "./example_directory" + http: + endpoint: "https://prebid.org" + use_rfc3986_compliant_request_builder: true + in_memory_cache: + type: "lru" + ttl_seconds: 300 + size_bytes: 1000 + cache_events: + enabled: true + endpoint: "https://prebid.org" + http_events: + endpoint: "https://prebid.org" + refresh_rate_seconds: 300 + timeout_ms: 100 gdpr: host_vendor_id: 15 default_value: "1" @@ -624,6 +654,18 @@ func TestFullConfig(t *testing.T) { cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "accounts.filesystem.enabled", true, cfg.Accounts.Files.Enabled) + cmpStrings(t, "accounts.filesystem.directorypath", "./example_directory", cfg.Accounts.Files.Path) + cmpStrings(t, "accounts.http.endpoint", "https://prebid.org", cfg.Accounts.HTTP.Endpoint) + cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", true, cfg.Accounts.HTTP.UseRfcCompliantBuilder) + cmpStrings(t, "accounts.in_memory_cache.type", "lru", cfg.Accounts.InMemoryCache.Type) + cmpInts(t, "accounts.in_memory_cache.ttl_seconds", 300, cfg.Accounts.InMemoryCache.TTL) + cmpInts(t, "accounts.in_memory_cache.size_bytes", 1000, cfg.Accounts.InMemoryCache.Size) + cmpBools(t, "accounts.cache_events.enabled", true, cfg.Accounts.CacheEvents.Enabled) + cmpStrings(t, "accounts.cache_events.endpoint", "https://prebid.org", cfg.Accounts.CacheEvents.Endpoint) + cmpStrings(t, "accounts.http_events.endpoint", "https://prebid.org", cfg.Accounts.HTTPEvents.Endpoint) + cmpInts(t, "accounts.http_events.refresh_rate_seconds", 300, int(cfg.Accounts.HTTPEvents.RefreshRate)) + cmpInts(t, "accounts.http_events.timeout_ms", 100, int(cfg.Accounts.HTTPEvents.Timeout)) cmpStrings(t, "cache.scheme", "http", cfg.CacheURL.Scheme) cmpStrings(t, "cache.host", "prebidcache.net", cfg.CacheURL.Host) cmpStrings(t, "cache.query", "uuid=%PBS_CACHE_UUID%", cfg.CacheURL.Query) From 20a81a9895a16639f69b9d1d9bf4d2cb2b5ee047 Mon Sep 17 00:00:00 2001 From: hhhjort <31041505+hhhjort@users.noreply.github.com> Date: Mon, 4 Aug 2025 13:08:36 -0400 Subject: [PATCH 046/272] Bidder throttling code to increase network stability. (#4415) * Adding request throttling to bidder requests * Add latency health * Adds new config options, metrics, and fixes * Set default window to 1000 and fix error type typo * Addresses PR comments * More PR feedback * Proper handling of the atomic uint in tests --- config/config.go | 22 +- errortypes/code.go | 1 + errortypes/errortypes.go | 19 ++ exchange/bidder.go | 109 +++++++++- exchange/bidder_health_test.go | 284 ++++++++++++++++++++++++++ exchange/bidder_validate_bids.go | 8 + exchange/bidder_validate_bids_test.go | 9 + exchange/exchange_test.go | 15 ++ metrics/config/metrics.go | 11 + metrics/go_metrics.go | 14 ++ metrics/metrics.go | 1 + metrics/metrics_mock.go | 4 + metrics/prometheus/prometheus.go | 12 ++ 13 files changed, 503 insertions(+), 6 deletions(-) create mode 100644 exchange/bidder_health_test.go diff --git a/config/config.go b/config/config.go index 80cdaa3335..3fd5092c5f 100644 --- a/config/config.go +++ b/config/config.go @@ -125,10 +125,24 @@ type PriceFloorFetcher struct { const MIN_COOKIE_SIZE_BYTES = 500 type HTTPClient struct { - MaxConnsPerHost int `mapstructure:"max_connections_per_host"` - MaxIdleConns int `mapstructure:"max_idle_connections"` - MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` - IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` + MaxConnsPerHost int `mapstructure:"max_connections_per_host"` + MaxIdleConns int `mapstructure:"max_idle_connections"` + MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` + IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` + Throttle HTTPThrottle `mapstructure:"throttle"` +} + +type HTTPThrottle struct { + // Enables bidder throttling + EnableThrottling bool `mapstructure:"enable_throttling"` + // If enabled, we will only log that the bidder was to be throttled, but not actually throttle it. + SimulateThrottlingOnly bool `mapstructure:"simulate_throttling_only"` + // Queue wait time that is considered unhealthy + LongQueueWaitThresholdMS int `mapstructure:"long_queue_wait_threshold_ms"` + // Queue wait time that is short enough to be considered a healthy signal + ShortQueueWaitThresholdMS int `mapstructure:"short_queue_wait_threshold_ms"` + // ThrottleWindow controls the speed that the throttling logic will react to changes in the health of the bidder. + ThrottleWindow int `mapstructure:"throttle_window"` } func (cfg *Configuration) validate(v *viper.Viper) []error { diff --git a/errortypes/code.go b/errortypes/code.go index 47e5292257..2e20f8ff9d 100644 --- a/errortypes/code.go +++ b/errortypes/code.go @@ -18,6 +18,7 @@ const ( FailedToMarshalErrorCode FailedToUnmarshalErrorCode InvalidImpFirstPartyDataErrorCode + BidderTemporarilyThrottledErrorCode ) // Defines numeric codes for well-known warnings. diff --git a/errortypes/errortypes.go b/errortypes/errortypes.go index 4e51847b5e..fe833adb8e 100644 --- a/errortypes/errortypes.go +++ b/errortypes/errortypes.go @@ -178,6 +178,25 @@ func (err *BidderTemporarilyDisabled) Severity() Severity { return SeverityWarning } +// BidderThrottled is used when a bidder is temporarily disabled due to throttling. +// This is a per request throttling, so subsequent requests may be allowed. +// The initial usecase is to flag bidders that are temporarily disabled due to high error rates or other issues. +type BidderThrottled struct { + Message string +} + +func (err *BidderThrottled) Error() string { + return err.Message +} + +func (err *BidderThrottled) Code() int { + return BidderTemporarilyThrottledErrorCode +} + +func (err *BidderThrottled) Severity() Severity { + return SeverityWarning +} + // MalformedAcct should be used when the retrieved account config cannot be unmarshaled // These errors will be written to http.ResponseWriter before canceling execution type MalformedAcct struct { diff --git a/exchange/bidder.go b/exchange/bidder.go index 232da470fb..cd3bb36919 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -9,11 +9,14 @@ import ( "errors" "fmt" "io" + "math" + "math/rand" "net/http" "net/http/httptrace" "regexp" "strings" "sync" + "sync/atomic" "time" "github.com/golang/glog" @@ -61,6 +64,10 @@ type AdaptedBidder interface { // Any errors will be user-facing in the API. // Error messages should help publishers understand what might account for "bad" bids. requestBid(ctx context.Context, bidderRequest BidderRequest, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, adsCertSigner adscert.Signer, bidRequestOptions bidRequestOptions, alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes, hookExecutor hookexecution.StageExecutor, ruleToAdjustments openrtb_ext.AdjustmentsByDealID) ([]*entities.PbsOrtbSeatBid, extraBidderRespInfo, []error) + // logHealthCheck registers a health check for the bidder. True for a healthy result, false for an unhealthy result. + logHealthCheck(success bool) + // shouldRequest returns true if a request should be made to the bidder. + shouldRequest() bool } // bidRequestOptions holds additional options for bid request execution to maintain clean code and reasonable number of parameters @@ -98,7 +105,7 @@ const ( // The name refers to the "Adapter" architecture pattern, and should not be confused with a Prebid "Adapter" // (which is being phased out and replaced by Bidder for OpenRTB auctions) func AdaptBidder(bidder adapters.Bidder, client *http.Client, cfg *config.Configuration, me metrics.MetricsEngine, name openrtb_ext.BidderName, debugInfo *config.DebugInfo, endpointCompression string) AdaptedBidder { - return &BidderAdapter{ + ba := &BidderAdapter{ Bidder: bidder, BidderName: name, Client: client, @@ -108,8 +115,23 @@ func AdaptBidder(bidder adapters.Bidder, client *http.Client, cfg *config.Config DisableConnMetrics: cfg.Metrics.Disabled.AdapterConnectionMetrics, DebugInfo: config.DebugInfo{Allow: parseDebugInfo(debugInfo)}, EndpointCompression: endpointCompression, + ThrottleConfig: bidderAdapterThrottleConfig{ + enabled: cfg.Client.Throttle.EnableThrottling, + simulateOnly: cfg.Client.Throttle.SimulateThrottlingOnly, + longQueueWaitThreshold: time.Duration(cfg.Client.Throttle.LongQueueWaitThresholdMS) * time.Millisecond, + shortQueueWaitThreshold: time.Duration(cfg.Client.Throttle.ShortQueueWaitThresholdMS) * time.Millisecond, + throttleWindow: cfg.Client.Throttle.ThrottleWindow, + }, }, } + if ba.config.ThrottleConfig.throttleWindow <= 0 { + ba.config.ThrottleConfig.throttleWindow = 1000 + } + // Precalculate bulk and delta values for health updates. + ba.config.ThrottleConfig.deltaValue = 1.0 / float64(ba.config.ThrottleConfig.throttleWindow) + ba.config.ThrottleConfig.bulkValue = 1.0 - ba.config.ThrottleConfig.deltaValue + + return ba } func parseDebugInfo(info *config.DebugInfo) bool { @@ -125,6 +147,8 @@ type BidderAdapter struct { Client *http.Client me metrics.MetricsEngine config bidderAdapterConfig + healthBits atomic.Uint64 // use atomic on this + } type bidderAdapterConfig struct { @@ -132,6 +156,22 @@ type bidderAdapterConfig struct { DisableConnMetrics bool DebugInfo config.DebugInfo EndpointCompression string + ThrottleConfig bidderAdapterThrottleConfig +} + +type bidderAdapterThrottleConfig struct { + // Enables bidder throttling + enabled bool + // If enabled, we will only log that the bidder was to be throttled, but not actually throttle it. + simulateOnly bool + // Queue wait time that is considered unhealthy + longQueueWaitThreshold time.Duration + // Queue wait time that is short enough to be considered a healthy signal + shortQueueWaitThreshold time.Duration + // throttleWindow controls the speed that the throttling logic will react to changes in the health of the bidder. + throttleWindow int + bulkValue float64 + deltaValue float64 } func (bidder *BidderAdapter) requestBid(ctx context.Context, bidderRequest BidderRequest, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, adsCertSigner adscert.Signer, bidRequestOptions bidRequestOptions, alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes, hookExecutor hookexecution.StageExecutor, ruleToAdjustments openrtb_ext.AdjustmentsByDealID) ([]*entities.PbsOrtbSeatBid, extraBidderRespInfo, []error) { @@ -527,7 +567,13 @@ func makeExt(httpInfo *httpCallInfo) *openrtb_ext.ExtHttpCall { // doRequest makes a request, handles the response, and returns the data needed by the // Bidder interface. func (bidder *BidderAdapter) doRequest(ctx context.Context, req *adapters.RequestData, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo { - return bidder.doRequestImpl(ctx, req, glog.Warningf, bidderRequestStartTime, tmaxAdjustments) + if bidder.shouldRequest() { + return bidder.doRequestImpl(ctx, req, glog.Warningf, bidderRequestStartTime, tmaxAdjustments) + } + return &httpCallInfo{ + request: req, + err: &errortypes.BidderThrottled{Message: fmt.Sprintf("Bidder %s is temporarily throttled", bidder.BidderName)}, + } } func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.RequestData, logger util.LogMsg, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo { @@ -567,6 +613,7 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re httpCallStart := time.Now() httpResp, err := ctxhttp.Do(ctx, bidder.Client, httpReq) if err != nil { + bidder.logHealthCheck(false) if err == context.DeadlineExceeded { err = &errortypes.Timeout{Message: err.Error()} var corebidder adapters.Bidder = bidder.Bidder @@ -600,11 +647,15 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re defer httpResp.Body.Close() if httpResp.StatusCode < 200 || httpResp.StatusCode >= 400 { + if httpResp.StatusCode >= 500 { + bidder.logHealthCheck(false) + } err = &errortypes.BadServerResponse{ Message: fmt.Sprintf("Server responded with failure status: %d. Set request.test = 1 for debugging info.", httpResp.StatusCode), } } + bidder.logHealthCheck(true) bidder.me.RecordBidderServerResponseTime(time.Since(httpCallStart)) return &httpCallInfo{ request: req, @@ -678,6 +729,17 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context // GotConn is called after a successful connection is obtained GotConn: func(info httptrace.GotConnInfo) { connWaitTime := time.Since(connStart) + if info.Reused { + // If the connection was reused, this is the time we waited in the pool + if bidder.config.ThrottleConfig.longQueueWaitThreshold > 0 && connWaitTime > bidder.config.ThrottleConfig.longQueueWaitThreshold { + bidder.logHealthCheck(false) // Mark as unhealthy if wait was too long + } else if bidder.config.ThrottleConfig.shortQueueWaitThreshold > 0 && connWaitTime < bidder.config.ThrottleConfig.shortQueueWaitThreshold { + bidder.logHealthCheck(true) // Mark as healthy if wait was short + // Note if there is a short wait time for the pool, but the auction times out, + // we would mark the bidder as healthy once and unhealthy once, pushing the + // health to 0.5 + } + } bidder.me.RecordAdapterConnections(bidder.BidderName, info.Reused, connWaitTime) }, @@ -785,3 +847,46 @@ var gzipWriterPool = sync.Pool{ return gzip.NewWriter(nil) }, } + +func (bidder *BidderAdapter) getHealth() float64 { + return math.Float64frombits(bidder.healthBits.Load()) +} + +const maxLoggingTries = 5 + +// logHealthCheck registers a health check for the bidder. True for a healthy result, false for an unhealthy result. +func (bidder *BidderAdapter) logHealthCheck(success bool) { + if !bidder.config.ThrottleConfig.enabled { + // Don't update health if throttling is not enabled + return + } + old := bidder.getHealth() + var newVal float64 + if success { + newVal = bidder.config.ThrottleConfig.bulkValue * old + } else { + newVal = bidder.config.ThrottleConfig.bulkValue*old + bidder.config.ThrottleConfig.deltaValue + } + // There is a race condition where under heavy traffic multiple attempts to update health can happen at the same time. + // This will result in health changing slower than otherwise. This might be a good thing, as it will prevent + // the bidder's health from changing too quickly in these conditions. + bidder.healthBits.Store(math.Float64bits(newVal)) +} + +func (bidder *BidderAdapter) shouldRequest() bool { + if !bidder.config.ThrottleConfig.enabled { + return true + } + health := bidder.getHealth() + if health < 0.2 { + return true + } + // Probability of returning false ramps from 0 at 0.2 to 0.9 at 1.0 + // Linear interpolation: p = (health - 0.2) / 0.8 * 0.9 + p := ((health - 0.2) / 0.8) * 0.9 + if rand.Float64() < p { + bidder.me.RecordAdapterThrottled(bidder.BidderName) + return bidder.config.ThrottleConfig.simulateOnly + } + return true +} diff --git a/exchange/bidder_health_test.go b/exchange/bidder_health_test.go new file mode 100644 index 0000000000..1fa7748923 --- /dev/null +++ b/exchange/bidder_health_test.go @@ -0,0 +1,284 @@ +package exchange + +import ( + "math" + "math/rand" + "sync" + "testing" + + "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v3/metrics/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func newTestAdapter() *BidderAdapter { + return &BidderAdapter{ + me: &config.NilMetricsEngine{}, + config: bidderAdapterConfig{ + ThrottleConfig: bidderAdapterThrottleConfig{ + enabled: true, + throttleWindow: 100, + bulkValue: 0.99, + deltaValue: 0.01, + }, + }, + } +} + +func TestBidderAdapter_LogHealthCheck(t *testing.T) { + testCases := []struct { + name string + initialHealth float64 + success bool + expectedRange struct { + min float64 + max float64 + } + }{ + { + name: "success with zero initial health", + initialHealth: 0.0, + success: true, + expectedRange: struct { + min float64 + max float64 + }{ + min: -0.001, // Allow for small floating point errors + max: 0.001, + }, + }, + { + name: "failure with zero initial health", + initialHealth: 0.0, + success: false, + expectedRange: struct { + min float64 + max float64 + }{ + min: 0.009, // 0.99*0 + 0.01 = 0.01 + max: 0.011, // Allow for small floating point errors + }, + }, + { + name: "success with 0.5 initial health", + initialHealth: 0.5, + success: true, + expectedRange: struct { + min float64 + max float64 + }{ + min: 0.485, // 0.99*0.5 = 0.495 + max: 0.505, // Allow for small floating point errors + }, + }, + { + name: "failure with 0.5 initial health", + initialHealth: 0.5, + success: false, + expectedRange: struct { + min float64 + max float64 + }{ + min: 0.495, // 0.99*0.5 + 0.01 = 0.505 + max: 0.515, // Allow for small floating point errors + }, + }, + { + name: "success with 1.0 initial health", + initialHealth: 1.0, + success: true, + expectedRange: struct { + min float64 + max float64 + }{ + min: 0.98, // 0.99*1.0 = 0.99 + max: 1.0, // Allow for small floating point errors + }, + }, + { + name: "failure with 1.0 initial health", + initialHealth: 1.0, + success: false, + expectedRange: struct { + min float64 + max float64 + }{ + min: 0.99, // 0.99*1.0 + 0.01 = 1.0 + max: 1.001, // Allow for small floating point errors + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a new BidderAdapter with the initial health value + bidder := newTestAdapter() + bidder.healthBits.Store(math.Float64bits(tc.initialHealth)) + + // Call the logHealthCheck method + bidder.logHealthCheck(tc.success) + + // Check the result is within expected range + actual := bidder.getHealth() + assert.True(t, actual >= tc.expectedRange.min && actual <= tc.expectedRange.max, + "Health value %f should be between %f and %f", actual, tc.expectedRange.min, tc.expectedRange.max) + }) + } +} + +func TestBidderAdapter_LogHealthCheck_ConcurrentAccess(t *testing.T) { + bidder := newTestAdapter() + bidder.healthBits.Store(math.Float64bits(0.5)) // Start at 0.5 + + const numGoroutines = 100 + const updatesPerGoroutine = 10 + var wg sync.WaitGroup + wg.Add(numGoroutines) + + // Launch multiple goroutines to update health concurrently + for i := 0; i < numGoroutines; i++ { + go func(routineNum int) { + defer wg.Done() + // Alternate between success and failure + success := routineNum%2 == 0 + for j := 0; j < updatesPerGoroutine; j++ { + bidder.logHealthCheck(success) + } + }(i) + } + + wg.Wait() + + // Check that the final health value is valid + health := bidder.getHealth() + assert.False(t, math.IsNaN(health), "Health should not be NaN") + assert.False(t, math.IsInf(health, 0), "Health should not be infinite") + assert.True(t, health >= 0, "Health should not be negative") +} + +func TestBidderAdapter_ShouldRequest(t *testing.T) { + testCases := []struct { + name string + healthValue float64 + expectedAlways bool + description string + }{ + { + name: "health below threshold", + healthValue: 0.1, + expectedAlways: true, + description: "When health < 0.2, shouldRequest should always return true", + }, + { + name: "health at threshold", + healthValue: 0.21, + expectedAlways: false, + description: "When health = 0.2, shouldRequest should be probabilistic", + }, + { + name: "health above threshold", + healthValue: 0.6, + expectedAlways: false, + description: "When health > 0.2, shouldRequest should be probabilistic", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a new BidderAdapter with the given health value + meMock := metrics.MetricsEngineMock{} + var biddername openrtb_ext.BidderName + meMock.On("RecordAdapterThrottled", biddername).Return() + bidder := newTestAdapter() + bidder.me = &meMock + bidder.healthBits.Store(math.Float64bits(tc.healthValue)) + + if tc.expectedAlways { + // Test multiple times to ensure it's consistently returning true + for i := 0; i < 100; i++ { + result := bidder.shouldRequest() + assert.True(t, result, tc.description) + } + } else { + // For probabilistic cases, we'll test that it sometimes returns false by running many iterations + const numTests = 1000 + throttledCount := 0 + passedCount := 0 + + for i := 0; i < numTests; i++ { + if bidder.shouldRequest() { + passedCount++ + // t.Log("Health check returned true on iteration", i, "for health value", tc.healthValue) + } else { + throttledCount++ + // t.Log("Health check returned false on iteration", i, "for health value", tc.healthValue) + } + } + + // We should see at least some false responses if the health is above 0.2 + if tc.healthValue > 0.2 { + assert.True(t, throttledCount > 0, "Expected at least some false responses for health %f", tc.healthValue) + meMock.AssertNumberOfCalls(t, "RecordAdapterThrottled", throttledCount) + } + } + }) + } +} + +func TestBidderAdapter_HealthIntegration(t *testing.T) { + // Test integration between logHealthCheck and shouldRequest + bidder := newTestAdapter() + + // Start with zero health - should always request + bidder.healthBits.Store(math.Float64bits(0.0)) + + // Check initial state + assert.Equal(t, float64(0.0), bidder.getHealth()) + assert.True(t, bidder.shouldRequest(), "Should initially always request with zero health") + + // Log many failures to increase health + for i := 0; i < 100; i++ { + bidder.logHealthCheck(false) + } + + // Now health should be higher, near 1.0 + health := bidder.getHealth() + assert.True(t, health > 0.5, "Health should increase with failures (current: %f)", health) + + // With higher health, some requests should be throttled + // Since shouldRequest has randomness, we need to run it many times + const numTests = 1000 + throttledCount := 0 + for i := 0; i < numTests; i++ { + rand.Seed(int64(i)) // For deterministic testing + if !bidder.shouldRequest() { + throttledCount++ + } + } + + // We should see some throttled requests now + assert.True(t, throttledCount > 0, "Expected some requests to be throttled with high health") + t.Logf("Health: %f, Throttled: %d/%d", health, throttledCount, numTests) + + // Now log many successes to decrease health + for i := 0; i < 100; i++ { + bidder.logHealthCheck(true) + } + + // Health should decrease + newHealth := bidder.getHealth() + assert.True(t, newHealth < health, "Health should decrease with successes (before: %f, after: %f)", health, newHealth) +} + +func TestBidderAdapter_GetHealth(t *testing.T) { + testValues := []float64{0.0, 0.1, 0.5, 0.99, 1.0} + + for _, val := range testValues { + bidder := newTestAdapter() + bidder.healthBits.Store(math.Float64bits(val)) + + actual := bidder.getHealth() + assert.InDelta(t, val, actual, 0.000001, "getHealth() should return the stored health value") + } +} diff --git a/exchange/bidder_validate_bids.go b/exchange/bidder_validate_bids.go index d028008132..5c5da548cb 100644 --- a/exchange/bidder_validate_bids.go +++ b/exchange/bidder_validate_bids.go @@ -41,6 +41,14 @@ func (v *validatedBidder) requestBid(ctx context.Context, bidderRequest BidderRe return seatBids, extraBidderRespInfo, errs } +func (v *validatedBidder) logHealthCheck(success bool) { + v.bidder.logHealthCheck(success) +} + +func (v *validatedBidder) shouldRequest() bool { + return v.bidder.shouldRequest() +} + // validateBids will run some validation checks on the returned bids and excise any invalid bids func removeInvalidBids(request *openrtb2.BidRequest, seatBid *entities.PbsOrtbSeatBid, debug bool) []error { // Exit early if there is nothing to do. diff --git a/exchange/bidder_validate_bids_test.go b/exchange/bidder_validate_bids_test.go index e14efec402..b611ca8175 100644 --- a/exchange/bidder_validate_bids_test.go +++ b/exchange/bidder_validate_bids_test.go @@ -363,3 +363,12 @@ type mockAdaptedBidder struct { func (b *mockAdaptedBidder) requestBid(ctx context.Context, bidderRequest BidderRequest, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, adsCertSigner adscert.Signer, bidRequestMetadata bidRequestOptions, alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes, executor hookexecution.StageExecutor, ruleToAdjustments openrtb_ext.AdjustmentsByDealID) ([]*entities.PbsOrtbSeatBid, extraBidderRespInfo, []error) { return b.bidResponse, b.extraRespInfo, b.errorResponse } + +func (b *mockAdaptedBidder) logHealthCheck(success bool) { + // No-op +} + +func (b *mockAdaptedBidder) shouldRequest() bool { + // Always return the healthy response. + return true +} diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index dcd8dcdec7..9200a1f8e4 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -5660,6 +5660,14 @@ func (b *validatingBidder) requestBid(ctx context.Context, bidderRequest BidderR return } +func (b *validatingBidder) logHealthCheck(success bool) { + // This is a no-op. +} + +func (b *validatingBidder) shouldRequest() bool { + return true +} + type capturingRequestBidder struct { req *openrtb2.BidRequest } @@ -5775,6 +5783,13 @@ func (panicingAdapter) requestBid(ctx context.Context, bidderRequest BidderReque panic("Panic! Panic! The world is ending!") } +func (panicingAdapter) logHealthCheck(success bool) { + // This is a no-op, but it is required to implement the Adapter interface. +} +func (panicingAdapter) shouldRequest() bool { + return true +} + func blankAdapterConfig(bidderList []openrtb_ext.BidderName) map[string]config.Adapter { adapters := make(map[string]config.Adapter) for _, b := range bidderList { diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index dcb330c47f..563f632e1a 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -371,6 +371,13 @@ func (me *MultiMetricsEngine) RecordModuleTimeout(labels metrics.ModuleLabels) { } } +// RecordAdapterThrottled across all engines +func (me *MultiMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderName) { + for _, thisME := range *me { + thisME.RecordAdapterThrottled(adapter) + } +} + // NilMetricsEngine implements the MetricsEngine interface where no metrics are actually captured. This is // used if no metric backend is configured and also for tests. type NilMetricsEngine struct{} @@ -546,3 +553,7 @@ func (me *NilMetricsEngine) RecordModuleExecutionError(labels metrics.ModuleLabe func (me *NilMetricsEngine) RecordModuleTimeout(labels metrics.ModuleLabels) { } + +// RecordAdapterThrottled as a noop +func (me *NilMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderName) { +} diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index 428b1891e6..4e015fa282 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -101,6 +101,7 @@ type AdapterMetrics struct { ConnWaitTime metrics.Timer BuyerUIDScrubbed metrics.Meter GDPRRequestBlocked metrics.Meter + ThrottledMeter metrics.Meter BidValidationCreativeSizeErrorMeter metrics.Meter BidValidationCreativeSizeWarnMeter metrics.Meter @@ -401,6 +402,7 @@ func makeBlankAdapterMetrics(disabledMetrics config.DisabledMetrics) *AdapterMet BidsReceivedMeter: blankMeter, PanicMeter: blankMeter, MarkupMetrics: makeBlankBidMarkupMetrics(), + ThrottledMeter: blankMeter, } if !disabledMetrics.AdapterConnectionMetrics { newAdapter.ConnCreated = metrics.NilCounter{} @@ -490,6 +492,7 @@ func registerAdapterMetrics(registry metrics.Registry, adapterOrAccount string, am.PanicMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.requests.panic", adapterOrAccount, exchange), registry) am.BuyerUIDScrubbed = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.buyeruid_scrubbed", adapterOrAccount, exchange), registry) am.GDPRRequestBlocked = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.gdpr_request_blocked", adapterOrAccount, exchange), registry) + am.ThrottledMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.requests.throttled", adapterOrAccount, exchange), registry) am.BidValidationCreativeSizeErrorMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.size.err", adapterOrAccount, exchange), registry) am.BidValidationCreativeSizeWarnMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.size.warn", adapterOrAccount, exchange), registry) @@ -1164,3 +1167,14 @@ func (me *Metrics) getModuleMetric(labels ModuleLabels) (*ModuleMetrics, error) return mm, nil } + +func (me *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { + adapterStr := adapterName.String() + am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] + if !ok { + glog.Errorf("Trying to log adapter throttled metric for %s: adapter not found", adapterStr) + return + } + + am.ThrottledMeter.Mark(1) +} diff --git a/metrics/metrics.go b/metrics/metrics.go index 45484cab7f..54fb355688 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -472,4 +472,5 @@ type MetricsEngine interface { RecordModuleSuccessRejected(labels ModuleLabels) RecordModuleExecutionError(labels ModuleLabels) RecordModuleTimeout(labels ModuleLabels) + RecordAdapterThrottled(adapterName openrtb_ext.BidderName) } diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index e979c6db72..d305113da8 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -226,3 +226,7 @@ func (me *MetricsEngineMock) RecordModuleExecutionError(labels ModuleLabels) { func (me *MetricsEngineMock) RecordModuleTimeout(labels ModuleLabels) { me.Called(labels) } + +func (me *MetricsEngineMock) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { + me.Called(adapterName) +} diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 7273a97f07..3c8adfcc9c 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -76,6 +76,7 @@ type Metrics struct { adapterBidResponseValidationSizeWarn *prometheus.CounterVec adapterBidResponseSecureMarkupError *prometheus.CounterVec adapterBidResponseSecureMarkupWarn *prometheus.CounterVec + adapterThrottled *prometheus.CounterVec // Syncer Metrics syncerRequests *prometheus.CounterVec @@ -427,6 +428,11 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "Count that tracks number of bids removed from bid response that had a invalid bidAdm (warn)", []string{adapterLabel, successLabel}) + metrics.adapterThrottled = newCounter(cfg, reg, + "adapter_throttled", + "Count of requests throttled labeled by adapter.", + []string{adapterLabel}) + metrics.overheadTimer = newHistogramVec(cfg, reg, "overhead_time_seconds", "Seconds to prepare adapter request or resolve adapter response", @@ -1089,3 +1095,9 @@ func (m *Metrics) RecordModuleTimeout(labels metrics.ModuleLabels) { stageLabel: labels.Stage, }).Inc() } + +func (m *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { + m.adapterThrottled.With(prometheus.Labels{ + adapterLabel: strings.ToLower(string(adapterName)), + }).Inc() +} From bb60bc87dd0a9231cccf91474bbafebc5109cc54 Mon Sep 17 00:00:00 2001 From: "yuu.t" Date: Wed, 6 Aug 2025 03:12:52 +0200 Subject: [PATCH 047/272] Yieldlab: Forward ADomain to OpenRTB bid (#4404) --- adapters/yieldlab/yieldlab.go | 17 +++++++++-------- .../yieldlab/yieldlabtest/exemplary/banner.json | 3 ++- .../yieldlab/yieldlabtest/exemplary/dsa.json | 3 ++- .../yieldlab/yieldlabtest/exemplary/gdpr.json | 3 ++- .../yieldlabtest/exemplary/mixed_types.json | 3 ++- .../exemplary/multiple_impressions.json | 6 ++++-- .../yieldlab/yieldlabtest/exemplary/schain.json | 3 ++- .../exemplary/schain_multiple_nodes.json | 3 ++- .../yieldlab/yieldlabtest/exemplary/video.json | 3 ++- .../yieldlabtest/exemplary/video_app.json | 3 ++- .../yieldlabtest/supplemental/dsa_empty.json | 3 ++- .../supplemental/dsa_empty_transparency.json | 3 ++- 12 files changed, 33 insertions(+), 20 deletions(-) diff --git a/adapters/yieldlab/yieldlab.go b/adapters/yieldlab/yieldlab.go index a241c5d386..4466e548af 100644 --- a/adapters/yieldlab/yieldlab.go +++ b/adapters/yieldlab/yieldlab.go @@ -363,14 +363,15 @@ func (a *YieldlabAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa } responseBid := &openrtb2.Bid{ - ID: strconv.FormatUint(bid.ID, 10), - Price: float64(bid.Price) / 100, - ImpID: imp.ID, - CrID: a.makeCreativeID(req, bid), - DealID: strconv.FormatUint(bid.Pid, 10), - W: int64(width), - H: int64(height), - Ext: extJson, + ID: strconv.FormatUint(bid.ID, 10), + Price: float64(bid.Price) / 100, + ImpID: imp.ID, + CrID: a.makeCreativeID(req, bid), + DealID: strconv.FormatUint(bid.Pid, 10), + W: int64(width), + H: int64(height), + ADomain: []string{bid.Advertiser}, + Ext: extJson, } var bidType openrtb_ext.BidType diff --git a/adapters/yieldlab/yieldlabtest/exemplary/banner.json b/adapters/yieldlab/yieldlabtest/exemplary/banner.json index 96fdc1410a..e08f5bb560 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/banner.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/banner.json @@ -105,7 +105,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/dsa.json b/adapters/yieldlab/yieldlabtest/exemplary/dsa.json index d8a9759b03..0c87f796c8 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/dsa.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/dsa.json @@ -160,7 +160,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/gdpr.json b/adapters/yieldlab/yieldlabtest/exemplary/gdpr.json index 25d90caf4f..e0d4835db5 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/gdpr.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/gdpr.json @@ -109,7 +109,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/mixed_types.json b/adapters/yieldlab/yieldlabtest/exemplary/mixed_types.json index 44fa57851c..0a982bc8ce 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/mixed_types.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/mixed_types.json @@ -131,7 +131,8 @@ "adm": "Yieldlab", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "video" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json b/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json index 1518e888fa..c43f08e725 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json @@ -132,7 +132,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" }, @@ -145,7 +146,8 @@ "impid": "test-imp-id2", "price": 1.31, "w": 300, - "h": 250 + "h": 250, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/schain.json b/adapters/yieldlab/yieldlabtest/exemplary/schain.json index 878a9fa4e1..4bdc5eb6df 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/schain.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/schain.json @@ -125,7 +125,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/schain_multiple_nodes.json b/adapters/yieldlab/yieldlabtest/exemplary/schain_multiple_nodes.json index af81b32a62..e0172ecc4d 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/schain_multiple_nodes.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/schain_multiple_nodes.json @@ -123,7 +123,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/video.json b/adapters/yieldlab/yieldlabtest/exemplary/video.json index b9d10123f7..37a3e1aa6a 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/video.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/video.json @@ -119,7 +119,8 @@ "adm": "Yieldlab", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "video" } diff --git a/adapters/yieldlab/yieldlabtest/exemplary/video_app.json b/adapters/yieldlab/yieldlabtest/exemplary/video_app.json index 8dbc5f97f6..bbe2f74331 100644 --- a/adapters/yieldlab/yieldlabtest/exemplary/video_app.json +++ b/adapters/yieldlab/yieldlabtest/exemplary/video_app.json @@ -119,7 +119,8 @@ "adm": "Yieldlab", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "video" } diff --git a/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty.json b/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty.json index 021339019a..a40c3d75a9 100644 --- a/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty.json +++ b/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty.json @@ -118,7 +118,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } diff --git a/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty_transparency.json b/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty_transparency.json index 6c2b0780c3..557a594a56 100644 --- a/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty_transparency.json +++ b/adapters/yieldlab/yieldlabtest/supplemental/dsa_empty_transparency.json @@ -130,7 +130,8 @@ "impid": "test-imp-id", "price": 2.01, "w": 728, - "h": 90 + "h": 90, + "adomain": ["yieldlab"] }, "type": "banner" } From 1fdb008cf84cdbfe4fb855ff056f3b4c92cc2db5 Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov Date: Wed, 6 Aug 2025 05:15:15 +0300 Subject: [PATCH 048/272] Yandex: Add video support (#4344) --- adapters/yandex/yandex.go | 100 ++++++++++--- .../yandextest/exemplary/multi-format.json | 137 ++++++++++++++++++ .../yandex/yandextest/exemplary/native.json | 7 +- .../yandextest/exemplary/simple-banner.json | 7 +- .../yandextest/exemplary/simple-video.json | 122 ++++++++++++++++ .../multiple-imps-some-malformed.json | 7 +- .../supplemental/multiple-imps.json | 12 +- .../simple-banner-empty-response.json | 7 +- .../simple-banner-empty-seatbid.json | 9 +- .../supplemental/simple-banner-sizes.json | 7 +- .../simple-banner-status-400.json | 7 +- .../simple-banner-unknown-imp.json | 7 +- .../simple-banner-unparsable-body.json | 7 +- .../supplemental/simple-video-options.json | 120 +++++++++++++++ ...own-banner.json => unknown-mediatype.json} | 2 +- .../supplemental/video-invalid-size.json | 37 +++++ static/bidder-info/yandex.yaml | 1 + 17 files changed, 564 insertions(+), 32 deletions(-) create mode 100644 adapters/yandex/yandextest/exemplary/multi-format.json create mode 100644 adapters/yandex/yandextest/exemplary/simple-video.json create mode 100644 adapters/yandex/yandextest/supplemental/simple-video-options.json rename adapters/yandex/yandextest/supplemental/{unknown-banner.json => unknown-mediatype.json} (96%) create mode 100644 adapters/yandex/yandextest/supplemental/video-invalid-size.json diff --git a/adapters/yandex/yandex.go b/adapters/yandex/yandex.go index 5a017c2bd6..51c7c7ec29 100644 --- a/adapters/yandex/yandex.go +++ b/adapters/yandex/yandex.go @@ -9,6 +9,7 @@ import ( "strings" "text/template" + "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/config" @@ -19,9 +20,25 @@ import ( ) const ( + bidderVersion = "1.1" + bidderName = "prebid.go" refererQueryKey = "target-ref" currencyQueryKey = "ssp-cur" impIdQueryKey = "imp-id" + videoMinDuration = 1 + videoMaxDuration = 120 +) + +// HTTP header constants +const ( + headerReferer = "Referer" + headerAcceptLanguage = "Accept-Language" + headerUserAgent = "User-Agent" + headerXForwardedFor = "X-Forwarded-For" + headerXRealIP = "X-Real-Ip" + headerContentType = "Content-Type" + headerAccept = "Accept" + headerXOpenRTVersion = "X-OpenRTB-Version" ) // Composite id of an ad placement @@ -101,13 +118,14 @@ func getHeaders(request *openrtb2.BidRequest) http.Header { if request.Device != nil && request.Site != nil { addNonEmptyHeaders(&headers, map[string]string{ - "Referer": request.Site.Page, - "Accept-Language": request.Device.Language, - "User-Agent": request.Device.UA, - "X-Forwarded-For": request.Device.IP, - "X-Real-Ip": request.Device.IP, - "Content-Type": "application/json;charset=utf-8", - "Accept": "application/json", + headerReferer: request.Site.Page, + headerAcceptLanguage: request.Device.Language, + headerUserAgent: request.Device.UA, + headerXForwardedFor: request.Device.IP, + headerXRealIP: request.Device.IP, + headerContentType: "application/json;charset=utf-8", + headerAccept: "application/json", + headerXOpenRTVersion: "2.5", }) } @@ -185,21 +203,40 @@ func mapExtToPlacementID(yandexExt openrtb_ext.ExtImpYandex) (*yandexPlacementID } func modifyImp(imp *openrtb2.Imp) error { + imp.DisplayManager = bidderName + imp.DisplayManagerVer = bidderVersion + + var hasSupportedType bool + if imp.Banner != nil { banner, err := modifyBanner(*imp.Banner) - if banner != nil { - imp.Banner = banner + if err != nil { + return err } - return err + imp.Banner = banner + hasSupportedType = true + } + + if imp.Video != nil { + video, err := modifyVideo(*imp.Video) + if err != nil { + return err + } + imp.Video = video + hasSupportedType = true } if imp.Native != nil { - return nil + hasSupportedType = true } - return &errortypes.BadInput{ - Message: fmt.Sprintf("Unsupported format. Yandex only supports banner and native types. Ignoring imp id #%s", imp.ID), + if !hasSupportedType { + return &errortypes.BadInput{ + Message: fmt.Sprintf("Unsupported format. Yandex only supports banner, video, and native types. Ignoring imp id #%s", imp.ID), + } } + + return nil } func modifyBanner(banner openrtb2.Banner) (*openrtb2.Banner, error) { @@ -220,6 +257,26 @@ func modifyBanner(banner openrtb2.Banner) (*openrtb2.Banner, error) { return &banner, nil } +func modifyVideo(video openrtb2.Video) (*openrtb2.Video, error) { + if video.W == nil || video.H == nil || *video.W == 0 || *video.H == 0 { + return nil, &errortypes.BadInput{ + Message: "Invalid size provided for Video", + } + } + + if video.MinDuration == 0 { + video.MinDuration = videoMinDuration + } + if video.MaxDuration == 0 { + video.MaxDuration = videoMaxDuration + } + if len(video.Protocols) == 0 { + video.Protocols = []adcom1.MediaCreativeSubtype{3} + } + + return &video, nil +} + // "Un-templates" the endpoint by replacing macroses and adding the required query parameters func (a *adapter) resolveUrl(placementID yandexPlacementID, referer string, currency string) (string, error) { params := macros.EndpointTemplateParams{PageID: placementID.PageID} @@ -327,15 +384,16 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData } func getBidType(imp openrtb2.Imp) (openrtb_ext.BidType, error) { - if imp.Native != nil { + switch { + case imp.Video != nil: + return openrtb_ext.BidTypeVideo, nil + case imp.Native != nil: return openrtb_ext.BidTypeNative, nil - } - - if imp.Banner != nil { + case imp.Banner != nil: return openrtb_ext.BidTypeBanner, nil - } - - return "", &errortypes.BadInput{ - Message: fmt.Sprintf("Processing an invalid impression; cannot resolve impression type for imp #%s", imp.ID), + default: + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Processing an invalid impression; cannot resolve impression type for imp #%s", imp.ID), + } } } diff --git a/adapters/yandex/yandextest/exemplary/multi-format.json b/adapters/yandex/yandextest/exemplary/multi-format.json new file mode 100644 index 0000000000..abec409aad --- /dev/null +++ b/adapters/yandex/yandextest/exemplary/multi-format.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4"], + "protocols": [3], + "minduration": 15, + "maxduration": 30 + }, + "native": { + "request": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":90}}]}}" + }, + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "headers": { + "Accept": ["application/json"], + "Accept-Language": ["en"], + "Content-Type": ["application/json;charset=utf-8"], + "Referer": ["http://example.com"], + "User-Agent": ["Mozilla/5.0"], + "X-Forwarded-For": ["192.168.1.1"], + "X-Real-Ip": ["192.168.1.1"], + "X-Openrtb-Version": ["2.5"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4"], + "protocols": [3], + "minduration": 15, + "maxduration": 30 + }, + "native": { + "request": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":90}}]}}" + }, + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "test-creative-id", + "w": 640, + "h": 480 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "test-creative-id", + "w": 640, + "h": 480 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/exemplary/native.json b/adapters/yandex/yandextest/exemplary/native.json index 880e4ca7b0..f438f6e0da 100644 --- a/adapters/yandex/yandextest/exemplary/native.json +++ b/adapters/yandex/yandextest/exemplary/native.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -60,6 +63,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "native": { "request": "{}", @@ -132,4 +137,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/exemplary/simple-banner.json b/adapters/yandex/yandextest/exemplary/simple-banner.json index aaa30ae901..cfb2236b24 100644 --- a/adapters/yandex/yandextest/exemplary/simple-banner.json +++ b/adapters/yandex/yandextest/exemplary/simple-banner.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -60,6 +63,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -132,4 +137,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/exemplary/simple-video.json b/adapters/yandex/yandextest/exemplary/simple-video.json new file mode 100644 index 0000000000..42871e4d66 --- /dev/null +++ b/adapters/yandex/yandextest/exemplary/simple-video.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "video-request-id", + "imp": [ + { + "id": "video-imp-id", + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4", "video/mpeg", "video/mp2t"], + "protocols": [3, 4, 5, 6], + "minduration": 0 + }, + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "headers": { + "Accept": ["application/json"], + "Accept-Language": ["en"], + "Content-Type": ["application/json;charset=utf-8"], + "Referer": ["http://example.com"], + "User-Agent": ["Mozilla/5.0"], + "X-Forwarded-For": ["192.168.1.1"], + "X-Real-Ip": ["192.168.1.1"], + "X-Openrtb-Version": ["2.5"] + }, + "body": { + "id": "video-request-id", + "imp": [ + { + "id": "video-imp-id", + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4", "video/mpeg", "video/mp2t"], + "protocols": [3, 4, 5, 6], + "minduration": 1, + "maxduration": 120 + }, + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "impIDs": ["video-imp-id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "video-bid-id", + "impid": "video-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "video-creative-id", + "w": 640, + "h": 480 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "video-bid-id", + "impid": "video-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "video-creative-id", + "w": 640, + "h": 480 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json index daffeb3add..c1b5aba636 100644 --- a/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json +++ b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json @@ -49,6 +49,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -66,6 +69,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id1", "banner": { "w": 300, @@ -143,4 +148,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps.json b/adapters/yandex/yandextest/supplemental/multiple-imps.json index 34d105fd52..50b7d0fe0f 100644 --- a/adapters/yandex/yandextest/supplemental/multiple-imps.json +++ b/adapters/yandex/yandextest/supplemental/multiple-imps.json @@ -52,6 +52,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -69,6 +72,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id1", "banner": { "w": 300, @@ -131,6 +136,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -148,6 +156,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id2", "banner": { "w": 400, @@ -234,4 +244,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json index 77aec13306..60ed42bcec 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -57,6 +60,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -98,4 +103,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json index b3e5e35214..9d4c10c6a1 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json @@ -3,6 +3,8 @@ "id": "request_id", "imp": [ { + "DisplayManager": "prebid.go", + "DisplayManagerVer": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -40,6 +42,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -57,6 +62,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -103,4 +110,4 @@ } ], "expectedMakeBidsErrors": [] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json index 66006513a4..1c215df0b9 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json @@ -110,6 +110,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -127,6 +130,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "no_size_but_valid_formats", "banner": { "w": 600, @@ -230,4 +235,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json index ed45e68653..8698c87a6b 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -57,6 +60,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -99,4 +104,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json index 991870a702..08c56dbc63 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -57,6 +60,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -122,4 +127,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json index 75c06a5f8d..9ef2e6b28a 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json @@ -40,6 +40,9 @@ "X-Forwarded-For": [ "127.0.0.1" ], + "X-Openrtb-Version": [ + "2.5" + ], "X-Real-Ip": [ "127.0.0.1" ], @@ -57,6 +60,8 @@ "id": "request_id", "imp": [ { + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", "id": "imp_id", "banner": { "w": 300, @@ -99,4 +104,4 @@ "comparison": "regex" } ] -} \ No newline at end of file +} diff --git a/adapters/yandex/yandextest/supplemental/simple-video-options.json b/adapters/yandex/yandextest/supplemental/simple-video-options.json new file mode 100644 index 0000000000..e139b37bdd --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-video-options.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "video-request-id", + "imp": [ + { + "id": "video-imp-id", + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4"] + }, + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "headers": { + "Accept": ["application/json"], + "Accept-Language": ["en"], + "Content-Type": ["application/json;charset=utf-8"], + "Referer": ["http://example.com"], + "User-Agent": ["Mozilla/5.0"], + "X-Forwarded-For": ["192.168.1.1"], + "X-Real-Ip": ["192.168.1.1"], + "X-Openrtb-Version": ["2.5"] + }, + "body": { + "id": "video-request-id", + "imp": [ + { + "id": "video-imp-id", + "video": { + "w": 640, + "h": 480, + "mimes": ["video/mp4"], + "protocols": [3], + "minduration": 1, + "maxduration": 120 + }, + "displaymanager": "prebid.go", + "displaymanagerver": "1.1", + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "impIDs": ["video-imp-id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "video-bid-id", + "impid": "video-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "video-creative-id", + "w": 640, + "h": 480 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "video-bid-id", + "impid": "video-imp-id", + "price": 1.5, + "adm": "YandexTest Video Ad00:00:30", + "crid": "video-creative-id", + "w": 640, + "h": 480 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/yandex/yandextest/supplemental/unknown-banner.json b/adapters/yandex/yandextest/supplemental/unknown-mediatype.json similarity index 96% rename from adapters/yandex/yandextest/supplemental/unknown-banner.json rename to adapters/yandex/yandextest/supplemental/unknown-mediatype.json index a01b903718..537fdcea6e 100644 --- a/adapters/yandex/yandextest/supplemental/unknown-banner.json +++ b/adapters/yandex/yandextest/supplemental/unknown-mediatype.json @@ -4,7 +4,7 @@ "imp": [ { "id": "imp_id", - "video": { + "audio": { "w": 100, "h": 200 }, diff --git a/adapters/yandex/yandextest/supplemental/video-invalid-size.json b/adapters/yandex/yandextest/supplemental/video-invalid-size.json new file mode 100644 index 0000000000..5a8793233b --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/video-invalid-size.json @@ -0,0 +1,37 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [3], + "minduration": 15, + "maxduration": 30 + }, + "ext": { + "bidder": { + "placement_id": "123-456" + } + } + } + ], + "site": { + "page": "http://example.com", + "domain": "example.com" + }, + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "language": "en" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid size provided for Video", + "comparison": "literal" + } + ], + "expectedBidderRequests": [] +} \ No newline at end of file diff --git a/static/bidder-info/yandex.yaml b/static/bidder-info/yandex.yaml index 8c5be2f70d..9ea1812cf7 100644 --- a/static/bidder-info/yandex.yaml +++ b/static/bidder-info/yandex.yaml @@ -7,6 +7,7 @@ capabilities: mediaTypes: - banner - native + - video userSync: redirect: url: https://yandex.ru/an/mapuid/yandex/?ssp-id=10500&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&location={{.RedirectURL}} From 23468de3fffc73814db69acabc5b2e4fbfc5cd26 Mon Sep 17 00:00:00 2001 From: Sigma Software Date: Thu, 7 Aug 2025 13:27:28 +0000 Subject: [PATCH 049/272] Request: Add hb_env=amp targeting to AMP responses (#4414) --- .../addtl-consent-through-query.json | 2 + .../gdpr-ccpa-through-query.json | 2 + ...dpr-legacy-tcf2-consent-through-query.json | 2 + .../gdpr-tcf1-consent-through-query.json | 2 + .../gdpr-tcf2-consent-through-query.json | 2 + .../aliased-buyeruids-case-insensitive.json | 2 + .../aliased-buyeruids.json | 2 + .../amp/valid-supplementary/aliases.json | 2 + .../buyeruids-camel-case.json | 2 + .../buyeruids-case-insensitive.json | 2 + .../gdpr-no-consentstring.json | 2 + .../amp/valid-supplementary/gdpr.json | 2 + .../imp-with-stored-resp.json | 2 + .../ortb-2.5-to-2.6-upconvert.json | 2 + .../openrtb2/sample-requests/hooks/amp.json | 2 + .../hooks/amp_bidder_reject.json | 2 + .../hooks/amp_bidder_response_reject.json | 2 + exchange/exchange.go | 10 +- exchange/exchange_test.go | 132 +++++++++++++++++ exchange/targeting.go | 6 +- exchange/targeting_test.go | 135 +++++++++++++++++- openrtb_ext/bid.go | 4 +- 22 files changed, 314 insertions(+), 7 deletions(-) diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json index c775d332ec..0fec67e82a 100644 --- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json +++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json @@ -120,6 +120,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json index ab9657d51f..9325deed2c 100644 --- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json +++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json @@ -112,6 +112,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json index 3d6c0bc015..0b2f2b9f59 100644 --- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json +++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json @@ -115,6 +115,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json index c4f3da140a..0ac1aabc89 100644 --- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json +++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json @@ -117,6 +117,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json index 2be461cdf6..32a46cc7c1 100644 --- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json +++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json @@ -115,6 +115,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json index 1d2462c98b..a2863164bb 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json @@ -64,6 +64,8 @@ "hb_cache_id_Appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_Appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_Appnexus": "amp", "hb_pb": "2.00", "hb_pb_Appnexus": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids.json index 3d6549fc60..70ad0869aa 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids.json @@ -64,6 +64,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "2.00", "hb_pb_appnexus": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliases.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliases.json index aebb320a66..bb60e5777d 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliases.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliases.json @@ -55,6 +55,8 @@ "hb_cache_id_unknown": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_unknow": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_unknown": "amp", "hb_pb": "2.00", "hb_pb_unknown": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json index 4597fe7786..96de1887e5 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json @@ -57,6 +57,8 @@ "hb_cache_id_YahooAds": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_YahooA": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_YahooAds": "amp", "hb_pb": "2.00", "hb_pb_YahooAds": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json index 976fcb3cf7..751fb17df4 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json @@ -57,6 +57,8 @@ "hb_cache_id_Appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_Appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_Appnexus": "amp", "hb_pb": "2.00", "hb_pb_Appnexus": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr-no-consentstring.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr-no-consentstring.json index dd961cf218..e5bc1bbb33 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr-no-consentstring.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr-no-consentstring.json @@ -53,6 +53,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "3.00", "hb_pb_appnexus": "3.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr.json index 137ad150f2..7c29162552 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/gdpr.json @@ -58,6 +58,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json index 4753707149..a066c46583 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json @@ -45,6 +45,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "5.00", "hb_pb_appnexus": "5.00" }, diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/ortb-2.5-to-2.6-upconvert.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/ortb-2.5-to-2.6-upconvert.json index 1a2db473cd..85ce5b7138 100644 --- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/ortb-2.5-to-2.6-upconvert.json +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/ortb-2.5-to-2.6-upconvert.json @@ -285,6 +285,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "15.00", "hb_pb_appnexus": "15.00" }, diff --git a/endpoints/openrtb2/sample-requests/hooks/amp.json b/endpoints/openrtb2/sample-requests/hooks/amp.json index a865f293e1..aee68bf5ff 100644 --- a/endpoints/openrtb2/sample-requests/hooks/amp.json +++ b/endpoints/openrtb2/sample-requests/hooks/amp.json @@ -52,6 +52,8 @@ "hb_cache_id_appnexus": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_appnex": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_appnexus": "amp", "hb_pb": "2.00", "hb_pb_appnexus": "2.00" }, diff --git a/endpoints/openrtb2/sample-requests/hooks/amp_bidder_reject.json b/endpoints/openrtb2/sample-requests/hooks/amp_bidder_reject.json index 7fc1e7d872..bf60e43913 100644 --- a/endpoints/openrtb2/sample-requests/hooks/amp_bidder_reject.json +++ b/endpoints/openrtb2/sample-requests/hooks/amp_bidder_reject.json @@ -57,6 +57,8 @@ "hb_cache_id_rubicon": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_rubico": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_rubicon": "amp", "hb_pb": "1.00", "hb_pb_rubicon": "1.00" }, diff --git a/endpoints/openrtb2/sample-requests/hooks/amp_bidder_response_reject.json b/endpoints/openrtb2/sample-requests/hooks/amp_bidder_response_reject.json index 4e38b5a2f2..49291bed7a 100644 --- a/endpoints/openrtb2/sample-requests/hooks/amp_bidder_response_reject.json +++ b/endpoints/openrtb2/sample-requests/hooks/amp_bidder_response_reject.json @@ -57,6 +57,8 @@ "hb_cache_id_rubicon": "0", "hb_cache_path": "/pbcache/endpoint", "hb_cache_path_rubico": "/pbcache/endpoint", + "hb_env": "amp", + "hb_env_rubicon": "amp", "hb_pb": "1.00", "hb_pb_rubicon": "1.00" }, diff --git a/exchange/exchange.go b/exchange/exchange.go index fcf12cad10..6a883a73ca 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -502,8 +502,16 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog errs = append(errs, cacheErrs...) } + env := "" + if r.BidRequestWrapper.BidRequest.App != nil { + env = openrtb_ext.EnvAppValue + } + if r.RequestType == "amp" { + env = openrtb_ext.EnvAmpValue + } + if targData.includeWinners || targData.includeBidderKeys || targData.includeFormat { - targData.setTargeting(auc, r.BidRequestWrapper.BidRequest.App != nil, bidCategory, r.Account.TruncateTargetAttribute, multiBidMap) + targData.setTargeting(auc, env, bidCategory, r.Account.TruncateTargetAttribute, multiBidMap) } } bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, *r, responseDebugAllow, requestExtPrebid.Passthrough, fledge, errs) diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index 9200a1f8e4..2e8fcbaa9d 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -6590,3 +6590,135 @@ type mockRequestValidator struct { func (mrv *mockRequestValidator) ValidateImp(imp *openrtb_ext.ImpWrapper, cfg ortb.ValidationConfig, index int, aliases map[string]string, hasStoredResponses bool, storedBidResponses stored_responses.ImpBidderStoredResp) []error { return mrv.errors } + +func TestAmpEnv(t *testing.T) { + type aTest struct { + desc string + requestType metrics.RequestType + expectedEnvInResponse string + } + testCases := []aTest{ + { + desc: "Amp request", + requestType: "amp", + expectedEnvInResponse: "amp", + }, + { + desc: "Non amp request", + requestType: "video", + expectedEnvInResponse: "", + }, + } + + // Set up test + type PrebidExt struct { + Prebid struct { + Targeting map[string]string `json:"targeting"` + } `json:"prebid"` + } + + noBidServer := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(204) + } + server := httptest.NewServer(http.HandlerFunc(noBidServer)) + defer server.Close() + + categoriesFetcher, err := newCategoryFetcher("./test/category-mapping") + if err != nil { + t.Errorf("Failed to create a category Fetcher: %v", err) + } + + e := new(exchange) + + e.cache = &wellBehavedCache{} + e.me = &metricsConf.NilMetricsEngine{} + e.gdprPermsBuilder = fakePermissionsBuilder{ + permissions: &permissionsMock{ + allowAllBidders: true, + }, + }.Builder + e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.categoriesFetcher = categoriesFetcher + e.requestSplitter = requestSplitter{ + me: &metricsConf.NilMetricsEngine{}, + gdprPermsBuilder: e.gdprPermsBuilder, + } + e.bidIDGenerator = &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false} + e.singleFormatBidders = map[openrtb_ext.BidderName]struct{}{ + "bidder": {}, + } + + bidderImpl := &goodSingleBidder{ + httpRequest: &adapters.RequestData{ + Method: "POST", + Uri: server.URL, + Body: []byte(""), + Headers: http.Header{}, + }, + bidResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "bid-id", + ImpID: "impression-id", + }, + BidType: openrtb_ext.BidTypeBanner, + }, + }, + }, + } + + e.adapterMap = map[openrtb_ext.BidderName]AdaptedBidder{ + openrtb_ext.BidderAppnexus: AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, ""), + } + ctx := context.Background() + + priceGran := openrtb_ext.PriceGranularity{ + Precision: ptrutil.ToPtr(2), + Ranges: []openrtb_ext.GranularityRange{}, + } + + bidRequest := &openrtb2.BidRequest{ + ID: "request-id", + Imp: []openrtb2.Imp{{ + ID: "impression-id", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}, {W: 300, H: 600}}}, + Ext: json.RawMessage(`{"prebid":{"bidder":{"appnexus": {"placementId": 1}}}}`), + }}, + } + + reqWrapper := openrtb_ext.RequestWrapper{BidRequest: bidRequest} + requestExt, err := reqWrapper.GetRequestExt() + if err != nil { + t.Fatalf("cannot get request ext: %v", err) + } + + requestExt.SetPrebid(&openrtb_ext.ExtRequestPrebid{ + Targeting: &openrtb_ext.ExtRequestTargeting{ + PriceGranularity: &priceGran, + IncludeBidderKeys: ptrutil.ToPtr(true), + IncludeWinners: ptrutil.ToPtr(true), + }, + }) + + for _, test := range testCases { + auctionRequest := &AuctionRequest{ + BidRequestWrapper: &reqWrapper, + Account: config.Account{DebugAllow: true}, + UserSyncs: &emptyUsersync{}, + StartTime: time.Now(), + HookExecutor: &hookexecution.EmptyHookExecutor{}, + TCF2Config: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), + RequestType: test.requestType, + } + + // Run test + outBidResponse, err := e.HoldAuction(ctx, auctionRequest, &DebugLog{}) + assert.NoErrorf(t, err, "%s. ex.HoldAuction returned an error: %v \n", test.desc, err) + + var responseExt PrebidExt + err = json.Unmarshal(outBidResponse.SeatBid[0].Bid[0].Ext, &responseExt) + assert.NoErrorf(t, err, "%s. Failed to Unmarshal HoldAuction response. The error: %v \n", test.desc, err) + assert.Equalf(t, test.expectedEnvInResponse, responseExt.Prebid.Targeting["hb_env"], "Response mismatch") + } +} diff --git a/exchange/targeting.go b/exchange/targeting.go index 0a689e4a32..d39c2cba0a 100644 --- a/exchange/targeting.go +++ b/exchange/targeting.go @@ -41,7 +41,7 @@ type targetData struct { // The one exception is the `hb_cache_id` key. Since our APIs explicitly document cache keys to be on a "best effort" basis, // it's ok if those stay in the auction. For now, this method implements a very naive cache strategy. // In the future, we should implement a more clever retry & backoff strategy to balance the success rate & performance. -func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMapping map[string]string, truncateTargetAttr *int, multiBidMap map[string]openrtb_ext.ExtMultiBid) { +func (targData *targetData) setTargeting(auc *auction, env string, categoryMapping map[string]string, truncateTargetAttr *int, multiBidMap map[string]openrtb_ext.ExtMultiBid) { for impId, topBidsPerImp := range auc.allBidsByBidder { overallWinner := auc.winningBids[impId] for originalBidderName, topBidsPerBidder := range topBidsPerImp { @@ -96,8 +96,8 @@ func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMappi targData.addKeys(targets, openrtb_ext.DealKey, topBid.Bid.DealID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } - if isApp { - targData.addKeys(targets, openrtb_ext.EnvKey, openrtb_ext.EnvAppValue, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) + if env != "" { + targData.addKeys(targets, openrtb_ext.EnvKey, env, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) } if len(categoryMapping) > 0 { targData.addKeys(targets, openrtb_ext.CategoryDurationKey, categoryMapping[topBid.Bid.ID], targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index c77239e998..db35656082 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -313,7 +313,7 @@ type TargetingTestData struct { Description string TargetData targetData Auction auction - IsApp bool + AppEnv string CategoryMapping map[string]string ExpectedPbsBids map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid TruncateTargetAttr *int @@ -1078,6 +1078,137 @@ var TargetingTests []TargetingTestData = []TargetingTestData{ }, }, }, + { + Description: "Empty targeting environment test", + TargetData: targetData{ + priceGranularity: lookupPriceGranularity("med"), + includeWinners: true, + prefix: DefaultKeyPrefix, + }, + AppEnv: "", + Auction: auction{ + allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: {{ + Bid: bid123, + BidType: openrtb_ext.BidTypeBanner, + }}, + }, + }, + }, + ExpectedPbsBids: map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "hb_bidder": "appnexus", + "hb_pb": "1.20", + }, + }, + }, + }, + }, + TruncateTargetAttr: nil, + }, + { + Description: "Amp targeting environment test", + TargetData: targetData{ + priceGranularity: lookupPriceGranularity("med"), + includeWinners: true, + prefix: DefaultKeyPrefix, + }, + AppEnv: openrtb_ext.EnvAmpValue, + Auction: auction{ + allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: {{ + Bid: bid123, + BidType: openrtb_ext.BidTypeBanner, + }}, + }, + }, + }, + ExpectedPbsBids: map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "hb_bidder": "appnexus", + "hb_pb": "1.20", + "hb_env": "amp", + }, + }, + }, + }, + }, + TruncateTargetAttr: nil, + }, + { + Description: "App targeting environment test", + TargetData: targetData{ + priceGranularity: lookupPriceGranularity("med"), + includeWinners: true, + prefix: DefaultKeyPrefix, + }, + AppEnv: openrtb_ext.EnvAppValue, + Auction: auction{ + allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: {{ + Bid: bid123, + BidType: openrtb_ext.BidTypeBanner, + }}, + }, + }, + }, + ExpectedPbsBids: map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "hb_bidder": "appnexus", + "hb_pb": "1.20", + "hb_env": "mobile-app", + }, + }, + }, + }, + }, + TruncateTargetAttr: nil, + }, + { + Description: "Custom targeting environment test", + TargetData: targetData{ + priceGranularity: lookupPriceGranularity("med"), + includeWinners: true, + prefix: DefaultKeyPrefix, + }, + AppEnv: "custom-targeting", + Auction: auction{ + allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: {{ + Bid: bid123, + BidType: openrtb_ext.BidTypeBanner, + }}, + }, + }, + }, + ExpectedPbsBids: map[string]map[openrtb_ext.BidderName][]ExpectedPbsBid{ + "ImpId-1": { + openrtb_ext.BidderAppnexus: []ExpectedPbsBid{ + { + BidTargets: map[string]string{ + "hb_bidder": "appnexus", + "hb_pb": "1.20", + "hb_env": "custom-targeting", + }, + }, + }, + }, + }, + TruncateTargetAttr: nil, + }, } func TestSetTargeting(t *testing.T) { @@ -1102,7 +1233,7 @@ func TestSetTargeting(t *testing.T) { } auc.winningBids = winningBids targData := test.TargetData - targData.setTargeting(auc, test.IsApp, test.CategoryMapping, test.TruncateTargetAttr, test.MultiBidMap) + targData.setTargeting(auc, test.AppEnv, test.CategoryMapping, test.TruncateTargetAttr, test.MultiBidMap) for imp, targetsByBidder := range test.ExpectedPbsBids { for bidder, expectedTargets := range targetsByBidder { for i, expected := range expectedTargets { diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go index 9856df241f..e8afbae3bd 100644 --- a/openrtb_ext/bid.go +++ b/openrtb_ext/bid.go @@ -141,7 +141,8 @@ type TargetingKey string const ( PbKey TargetingKey = "_pb" - // EnvKey exists to support the Prebid Universal Creative. If it exists, the only legal value is mobile-app. + // EnvKey exists to support the Prebid Universal Creative. + // If it exists, the only legal values are "mobile-app" and "amp". // It will exist only if the incoming bidRequest defined request.app instead of request.site. EnvKey TargetingKey = "_env" @@ -167,6 +168,7 @@ const ( // EnvAppValue used as a value for EnvKey EnvAppValue string = "mobile-app" + EnvAmpValue string = "amp" CategoryDurationKey TargetingKey = "_pb_cat_dur" ) From 804f6021db9c849c6902db3eaf5a13f332593bf4 Mon Sep 17 00:00:00 2001 From: Isha Bharti Date: Thu, 7 Aug 2025 19:08:34 +0530 Subject: [PATCH 050/272] Pubmatic: Forward skadn object in bid request (#4453) --- adapters/pubmatic/pubmatic.go | 12 ++++++--- .../pubmatictest/supplemental/app.json | 10 ++++++- .../pubmatictest/supplemental/impExt.json | 26 +++++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index 0126a76d00..7c112670cb 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -47,9 +47,10 @@ type pubmaticBidExtVideo struct { type ExtImpBidderPubmatic struct { adapters.ExtImpBidder - Data json.RawMessage `json:"data,omitempty"` - AE int `json:"ae,omitempty"` - GpId string `json:"gpid,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + AE int `json:"ae,omitempty"` + GpId string `json:"gpid,omitempty"` + SKAdnetwork json.RawMessage `json:"skadn,omitempty"` } type ExtAdServer struct { @@ -80,6 +81,7 @@ const ( AdServerKey = "adserver" PBAdslotKey = "pbadslot" gpIdKey = "gpid" + skAdnetworkKey = "skadn" ) func (a *PubmaticAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { @@ -336,6 +338,10 @@ func parseImpressionObject(imp *openrtb2.Imp, extractWrapperExtFromImp, extractP extMap[gpIdKey] = bidderExt.GpId } + if bidderExt.SKAdnetwork != nil { + extMap[skAdnetworkKey] = bidderExt.SKAdnetwork + } + imp.Ext = nil if len(extMap) > 0 { ext, err := json.Marshal(extMap) diff --git a/adapters/pubmatic/pubmatictest/supplemental/app.json b/adapters/pubmatic/pubmatictest/supplemental/app.json index e26b2c3609..e3db8f33a4 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/app.json +++ b/adapters/pubmatic/pubmatictest/supplemental/app.json @@ -27,6 +27,10 @@ "version": 1, "profile": 5123 } + }, + "skadn": { + "skadnetids": ["k674qkevps.skadnetwork"], + "version": "2.0" } } }], @@ -64,7 +68,11 @@ "bidfloor": 0.12, "ext": { "pmZoneId": "Zone1,Zone2", - "preference": "sports,movies" + "preference": "sports,movies", + "skadn": { + "skadnetids": ["k674qkevps.skadnetwork"], + "version": "2.0" + } } } ], diff --git a/adapters/pubmatic/pubmatictest/supplemental/impExt.json b/adapters/pubmatic/pubmatictest/supplemental/impExt.json index 707993446a..86c7447382 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/impExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/impExt.json @@ -33,7 +33,18 @@ "cricket" ] }, - "gpid":"/1111/home" + "gpid":"/1111/home", + "skadn": { + "versions": [ + "2.0", + "2.1" + ], + "sourceapp": "11111", + "skadnetids": [ + "424m5254lk.skadnetwork", + "4fzdc2evr5.skadnetwork" + ] + } } } ], @@ -70,7 +81,18 @@ "ext": { "dfp_ad_unit_code": "/1111/home", "key_val": "k1=v1|k2=v2|sport=rugby,cricket", - "gpid":"/1111/home" + "gpid":"/1111/home", + "skadn": { + "versions": [ + "2.0", + "2.1" + ], + "sourceapp": "11111", + "skadnetids": [ + "424m5254lk.skadnetwork", + "4fzdc2evr5.skadnetwork" + ] + } } } ], From fc9077f50f0e9bfaf2c087f1830e3e1cd37d9ab8 Mon Sep 17 00:00:00 2001 From: hhhjort <31041505+hhhjort@users.noreply.github.com> Date: Thu, 7 Aug 2025 13:11:45 -0400 Subject: [PATCH 051/272] Adds missing defaults to network throttling code (#4477) --- config/config.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/config.go b/config/config.go index 3fd5092c5f..2716f99077 100644 --- a/config/config.go +++ b/config/config.go @@ -959,6 +959,11 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("http_client.max_idle_connections", 400) v.SetDefault("http_client.max_idle_connections_per_host", 10) v.SetDefault("http_client.idle_connection_timeout_seconds", 60) + v.SetDefault("http_client.throttle.enable_throttling", false) + v.SetDefault("http_client.throttle.simulate_throttling_only", false) + v.SetDefault("http_client.throttle.long_queue_wait_threshold_ms", 50) + v.SetDefault("http_client.throttle.short_queue_wait_threshold_ms", 10) + v.SetDefault("http_client.throttle.throttle_window", 1000) v.SetDefault("http_client_cache.max_connections_per_host", 0) // unlimited v.SetDefault("http_client_cache.max_idle_connections", 10) v.SetDefault("http_client_cache.max_idle_connections_per_host", 2) From f1778be652a6691e50af27331edd1acf442de633 Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Thu, 7 Aug 2025 22:52:50 +0300 Subject: [PATCH 052/272] New Adapter: Tagoras - Vidazoo alias (#4329) Co-authored-by: anna-y-perion --- static/bidder-info/tagoras.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 static/bidder-info/tagoras.yaml diff --git a/static/bidder-info/tagoras.yaml b/static/bidder-info/tagoras.yaml new file mode 100644 index 0000000000..c40aaa2a04 --- /dev/null +++ b/static/bidder-info/tagoras.yaml @@ -0,0 +1,10 @@ +aliasOf: "vidazoo" +endpoint: "https://exchange.tagoras.io/openrtb/" +maintainer: + email: "prebid@tagoras.io" +userSync: + iframe: + url: https://sync.tagoras.io/api/user/html/6819bdc3e6bb44545c55f843?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} +openrtb: + version: 2.6 \ No newline at end of file From f7fade902718729e2c33e2393bfa72f0607af871 Mon Sep 17 00:00:00 2001 From: Anna Yablonsky Date: Thu, 7 Aug 2025 23:30:21 +0300 Subject: [PATCH 053/272] New Adapter: Omnidex - Vidazoo alias (#4441) --- static/bidder-info/omnidex.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/bidder-info/omnidex.yaml diff --git a/static/bidder-info/omnidex.yaml b/static/bidder-info/omnidex.yaml new file mode 100644 index 0000000000..66d53a2415 --- /dev/null +++ b/static/bidder-info/omnidex.yaml @@ -0,0 +1,8 @@ +aliasOf: "vidazoo" +endpoint: "https://exchange.omni-dex.io/openrtb/" +maintainer: + email: "dev@vidazoo.com" +userSync: + iframe: + url: https://sync.omni-dex.io/api/user/html/6810d0c7f163277130f3d7a9?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} From ae1c9e67242afee61e23df43991ff3d645524385 Mon Sep 17 00:00:00 2001 From: Scott Kay Date: Thu, 7 Aug 2025 20:43:40 -0400 Subject: [PATCH 054/272] Define An Adapter As White Label Only (#4461) --- config/bidderinfo.go | 40 ++++--- config/bidderinfo_test.go | 119 +++++++++++++-------- endpoints/info/bidders.go | 4 +- endpoints/info/bidders_detail.go | 4 +- endpoints/info/bidders_detail_test.go | 9 +- endpoints/info/bidders_test.go | 146 +++++++++++++++++++------- endpoints/openrtb2/auction.go | 5 +- endpoints/openrtb2/auction_test.go | 37 +++++-- exchange/adapter_util.go | 10 +- exchange/adapter_util_test.go | 73 ++++++++++++- usersync/syncersbuilder.go | 2 +- usersync/syncersbuilder_test.go | 15 +++ 12 files changed, 348 insertions(+), 116 deletions(-) diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 87771b402e..b67ed50825 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -21,10 +21,12 @@ type BidderInfos map[string]BidderInfo // BidderInfo specifies all configuration for a bidder except for enabled status, endpoint, and extra information. type BidderInfo struct { - AliasOf string `yaml:"aliasOf" mapstructure:"aliasOf"` - Disabled bool `yaml:"disabled" mapstructure:"disabled"` - Endpoint string `yaml:"endpoint" mapstructure:"endpoint"` - ExtraAdapterInfo string `yaml:"extra_info" mapstructure:"extra_info"` + AliasOf string `yaml:"aliasOf" mapstructure:"aliasOf"` + WhiteLabelOnly bool `yaml:"whiteLabelOnly" mapstructure:"whiteLabelOnly"` + Disabled bool `yaml:"disabled" mapstructure:"disabled"` + Endpoint string `yaml:"endpoint" mapstructure:"endpoint"` + ExtraAdapterInfo string `yaml:"extra_info" mapstructure:"extra_info"` + OpenRTB *OpenRTBInfo `yaml:"openrtb" mapstructure:"openrtb"` Maintainer *MaintainerInfo `yaml:"maintainer" mapstructure:"maintainer"` Capabilities *CapabilitiesInfo `yaml:"capabilities" mapstructure:"capabilities"` @@ -43,8 +45,7 @@ type BidderInfo struct { PlatformID string `yaml:"platform_id" mapstructure:"platform_id"` AppSecret string `yaml:"app_secret" mapstructure:"app_secret"` // EndpointCompression determines, if set, the type of compression the bid request will undergo before being sent to the corresponding bid server - EndpointCompression string `yaml:"endpointCompression" mapstructure:"endpointCompression"` - OpenRTB *OpenRTBInfo `yaml:"openrtb" mapstructure:"openrtb"` + EndpointCompression string `yaml:"endpointCompression" mapstructure:"endpointCompression"` } type aliasNillableFields struct { @@ -199,7 +200,7 @@ type SyncerEndpoint struct { } func (bi BidderInfo) IsEnabled() bool { - return !bi.Disabled + return !bi.WhiteLabelOnly && !bi.Disabled } // Defined returns true if at least one field exists, except for the supports field. @@ -407,15 +408,24 @@ func (infos BidderInfos) validate(errs []error) []error { } func validateAliases(aliasBidderInfo BidderInfo, infos BidderInfos, bidderName string) error { - if len(aliasBidderInfo.AliasOf) > 0 { - if parentBidder, ok := infos[aliasBidderInfo.AliasOf]; ok { - if len(parentBidder.AliasOf) > 0 { - return fmt.Errorf("bidder: %s cannot be an alias of an alias: %s", aliasBidderInfo.AliasOf, bidderName) - } - } else { - return fmt.Errorf("bidder: %s not found for an alias: %s", aliasBidderInfo.AliasOf, bidderName) - } + if aliasBidderInfo.AliasOf == "" { + return nil } + + if aliasBidderInfo.WhiteLabelOnly { + return fmt.Errorf("bidder: %s is an alias and cannot be set as white label only", bidderName) + } + + parentBidder, parentBidderFound := infos[aliasBidderInfo.AliasOf] + + if !parentBidderFound { + return fmt.Errorf("bidder: %s not found for an alias: %s", aliasBidderInfo.AliasOf, bidderName) + } + + if len(parentBidder.AliasOf) > 0 { + return fmt.Errorf("bidder: %s cannot be an alias of an alias: %s", aliasBidderInfo.AliasOf, bidderName) + } + return nil } diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 0b9547d0d6..e2270ed2f9 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -679,54 +679,53 @@ func TestBidderInfoValidationPositive(t *testing.T) { } func TestValidateAliases(t *testing.T) { - testCase := struct { - description string - bidderInfos BidderInfos - expectErrors []error + testCases := []struct { + name string + bidderName string + bidderInfo BidderInfo + bidderInfos BidderInfos + expectedErr error }{ - description: "invalid aliases", - bidderInfos: BidderInfos{ - "bidderA": BidderInfo{ - Endpoint: "http://bidderA.com/openrtb2", - Maintainer: &MaintainerInfo{ - Email: "maintainer@bidderA.com", - }, - Capabilities: &CapabilitiesInfo{ - Site: &PlatformInfo{ - MediaTypes: []openrtb_ext.BidType{ - openrtb_ext.BidTypeVideo, - }, - }, - }, - AliasOf: "bidderB", - }, - "bidderB": BidderInfo{ - Endpoint: "http://bidderA.com/openrtb2", - Maintainer: &MaintainerInfo{ - Email: "maintainer@bidderA.com", - }, - Capabilities: &CapabilitiesInfo{ - Site: &PlatformInfo{ - MediaTypes: []openrtb_ext.BidType{ - openrtb_ext.BidTypeVideo, - }, - }, - }, - AliasOf: "bidderC", - }, + { + name: "not-alias", + bidderName: "b", + bidderInfo: BidderInfo{}, + bidderInfos: BidderInfos{}, + expectedErr: nil, }, - expectErrors: []error{ - errors.New("bidder: bidderB cannot be an alias of an alias: bidderA"), - errors.New("bidder: bidderC not found for an alias: bidderB"), + { + name: "alias-not-found", + bidderName: "b", + bidderInfo: BidderInfo{AliasOf: "nonexistent"}, + bidderInfos: BidderInfos{}, + expectedErr: errors.New("bidder: nonexistent not found for an alias: b"), // does this make sense? should it be reversed? + }, + { + name: "alias-of-alias", + bidderName: "b", + bidderInfo: BidderInfo{AliasOf: "a"}, + bidderInfos: BidderInfos{"a": BidderInfo{AliasOf: "foo"}}, + expectedErr: errors.New("bidder: a cannot be an alias of an alias: b"), // does this make sense? should it be reversed? + }, + { + name: "whitelabelonly", + bidderName: "b", + bidderInfo: BidderInfo{AliasOf: "a", WhiteLabelOnly: true}, + bidderInfos: BidderInfos{"a": BidderInfo{}}, + expectedErr: errors.New("bidder: b is an alias and cannot be set as white label only"), }, } - var errs []error - for bidderName, bidderInfo := range testCase.bidderInfos { - errs = append(errs, validateAliases(bidderInfo, testCase.bidderInfos, bidderName)) + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := validateAliases(test.bidderInfo, test.bidderInfos, test.bidderName) + if test.expectedErr == nil { + assert.NoError(t, result) + } else { + assert.EqualError(t, result, test.expectedErr.Error()) + } + }) } - - assert.ElementsMatch(t, errs, testCase.expectErrors) } func TestBidderInfoValidationNegative(t *testing.T) { @@ -1563,6 +1562,42 @@ func TestSyncerEndpointOverride(t *testing.T) { } } +func TestBidderInfoIsEnabled(t *testing.T) { + testCases := []struct { + name string + bidder BidderInfo + expected bool + }{ + { + name: "enabled", + bidder: BidderInfo{Disabled: false}, + expected: true, + }, + { + name: "enabled-whitelabelonly", + bidder: BidderInfo{Disabled: false, WhiteLabelOnly: true}, + expected: false, + }, + { + name: "disabled", + bidder: BidderInfo{Disabled: true}, + expected: false, + }, + { + name: "disabled-whitelabelonly", + bidder: BidderInfo{Disabled: true, WhiteLabelOnly: true}, + expected: false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := test.bidder.IsEnabled() + assert.Equal(t, test.expected, result) + }) + } +} + func TestSyncerDefined(t *testing.T) { testCases := []struct { name string diff --git a/endpoints/info/bidders.go b/endpoints/info/bidders.go index 163f6cee5b..5de9c05a23 100644 --- a/endpoints/info/bidders.go +++ b/endpoints/info/bidders.go @@ -106,12 +106,12 @@ func prepareResponse(bidders config.BidderInfos, p bidderPredicate) ([]byte, err } func prepareBiddersResponseAll(bidders config.BidderInfos) ([]byte, error) { - filterNone := func(_ config.BidderInfo) bool { return true } + filterNone := func(info config.BidderInfo) bool { return !info.WhiteLabelOnly } return prepareResponse(bidders, filterNone) } func prepareBiddersResponseAllBaseOnly(bidders config.BidderInfos) ([]byte, error) { - filterBaseOnly := func(info config.BidderInfo) bool { return len(info.AliasOf) == 0 } + filterBaseOnly := func(info config.BidderInfo) bool { return !info.WhiteLabelOnly && len(info.AliasOf) == 0 } return prepareResponse(bidders, filterBaseOnly) } diff --git a/endpoints/info/bidders_detail.go b/endpoints/info/bidders_detail.go index fb9ce25216..098dad032e 100644 --- a/endpoints/info/bidders_detail.go +++ b/endpoints/info/bidders_detail.go @@ -78,7 +78,9 @@ func mapDetails(bidders config.BidderInfos) map[string]bidderDetail { details := map[string]bidderDetail{} for bidderName, bidderInfo := range bidders { - details[bidderName] = mapDetailFromConfig(bidderInfo) + if !bidderInfo.WhiteLabelOnly { + details[bidderName] = mapDetailFromConfig(bidderInfo) + } } return details diff --git a/endpoints/info/bidders_detail_test.go b/endpoints/info/bidders_detail_test.go index f86a52692d..d98e9ec094 100644 --- a/endpoints/info/bidders_detail_test.go +++ b/endpoints/info/bidders_detail_test.go @@ -72,6 +72,8 @@ func TestMapDetails(t *testing.T) { bidderBInfo = config.BidderInfo{Endpoint: "http://unsecureEndpoint.com", Disabled: false, Maintainer: &config.MaintainerInfo{Email: "bidderB"}} bidderBDetail = bidderDetail{Status: "ACTIVE", UsesHTTPS: ptrutil.ToPtr(false), Maintainer: &maintainer{Email: "bidderB"}} + + bidderCInfo = config.BidderInfo{WhiteLabelOnly: true, Endpoint: "https://secureEndpoint.com", Maintainer: &config.MaintainerInfo{Email: "bidderC"}} ) var testCases = []struct { @@ -89,9 +91,14 @@ func TestMapDetails(t *testing.T) { givenBidders: config.BidderInfos{"a": bidderAInfo}, expectedDetails: map[string]bidderDetail{"a": bidderADetail}, }, + { + name: "one-whitelabelonly", + givenBidders: config.BidderInfos{"c": bidderCInfo}, + expectedDetails: map[string]bidderDetail{}, + }, { name: "many", - givenBidders: config.BidderInfos{"a": bidderAInfo, "b": bidderBInfo}, + givenBidders: config.BidderInfos{"a": bidderAInfo, "b": bidderBInfo, "c": bidderCInfo}, expectedDetails: map[string]bidderDetail{"a": bidderADetail, "b": bidderBDetail}, }, } diff --git a/endpoints/info/bidders_test.go b/endpoints/info/bidders_test.go index b75b32aae1..20b5ea0401 100644 --- a/endpoints/info/bidders_test.go +++ b/endpoints/info/bidders_test.go @@ -12,10 +12,12 @@ import ( func TestPrepareBiddersResponseAll(t *testing.T) { var ( - enabledCore = config.BidderInfo{Disabled: false} - enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} - disabledCore = config.BidderInfo{Disabled: true} - disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + enabledCore = config.BidderInfo{Disabled: false} + enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} + enabledWhiteLabelOnly = config.BidderInfo{Disabled: false, WhiteLabelOnly: true} + disabledCore = config.BidderInfo{Disabled: true} + disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + disabledWhiteLabelOnly = config.BidderInfo{Disabled: true, WhiteLabelOnly: true} ) testCases := []struct { @@ -68,10 +70,25 @@ func TestPrepareBiddersResponseAll(t *testing.T) { givenBidders: config.BidderInfos{"z": enabledAlias, "a": enabledCore}, expected: `["a","z"]`, }, + { + name: "whitelabelonly-one-enabled", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-one-disabled", + givenBidders: config.BidderInfos{"a": disabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-many-mixed", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly, "b": disabledWhiteLabelOnly}, + expected: `[]`, + }, { name: "mixed", - givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": enabledCore, "d": enabledAlias}, - expected: `["a","b","c","d"]`, + givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": disabledWhiteLabelOnly, "d": enabledCore, "e": enabledAlias, "f": enabledWhiteLabelOnly}, + expected: `["a","b","d","e"]`, }, } @@ -86,10 +103,12 @@ func TestPrepareBiddersResponseAll(t *testing.T) { func TestPrepareBiddersResponseAllBaseOnly(t *testing.T) { var ( - enabledCore = config.BidderInfo{Disabled: false} - enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} - disabledCore = config.BidderInfo{Disabled: true} - disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + enabledCore = config.BidderInfo{Disabled: false} + enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} + enabledWhiteLabelOnly = config.BidderInfo{Disabled: false, WhiteLabelOnly: true} + disabledCore = config.BidderInfo{Disabled: true} + disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + disabledWhiteLabelOnly = config.BidderInfo{Disabled: true, WhiteLabelOnly: true} ) testCases := []struct { @@ -137,10 +156,25 @@ func TestPrepareBiddersResponseAllBaseOnly(t *testing.T) { givenBidders: config.BidderInfos{"a": enabledAlias, "b": enabledAlias}, expected: `[]`, }, + { + name: "whitelabelonly-one-enabled", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-one-disabled", + givenBidders: config.BidderInfos{"a": disabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-many", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly, "b": enabledWhiteLabelOnly}, + expected: `[]`, + }, { name: "mixed", - givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": enabledCore, "d": enabledAlias}, - expected: `["a","c"]`, + givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": disabledWhiteLabelOnly, "d": enabledCore, "e": enabledAlias, "f": enabledWhiteLabelOnly}, + expected: `["a","d"]`, }, } @@ -155,10 +189,12 @@ func TestPrepareBiddersResponseAllBaseOnly(t *testing.T) { func TestPrepareBiddersResponseEnabledOnly(t *testing.T) { var ( - enabledCore = config.BidderInfo{Disabled: false} - enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} - disabledCore = config.BidderInfo{Disabled: true} - disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + enabledCore = config.BidderInfo{Disabled: false} + enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} + enabledWhiteLabelOnly = config.BidderInfo{Disabled: false, WhiteLabelOnly: true} + disabledCore = config.BidderInfo{Disabled: true} + disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + disabledWhiteLabelOnly = config.BidderInfo{Disabled: true, WhiteLabelOnly: true} ) testCases := []struct { @@ -211,10 +247,25 @@ func TestPrepareBiddersResponseEnabledOnly(t *testing.T) { givenBidders: config.BidderInfos{"z": enabledAlias, "a": enabledCore}, expected: `["a","z"]`, }, + { + name: "whitelabelonly-one-enabled", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-one-disabled", + givenBidders: config.BidderInfos{"a": disabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-many-mixed", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly, "b": disabledWhiteLabelOnly}, + expected: `[]`, + }, { name: "mixed", - givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": enabledCore, "d": enabledAlias}, - expected: `["c","d"]`, + givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": disabledWhiteLabelOnly, "d": enabledCore, "e": enabledAlias, "f": enabledWhiteLabelOnly}, + expected: `["d","e"]`, }, } @@ -229,10 +280,12 @@ func TestPrepareBiddersResponseEnabledOnly(t *testing.T) { func TestPrepareBiddersResponseEnabledOnlyBaseOnly(t *testing.T) { var ( - enabledCore = config.BidderInfo{Disabled: false} - enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} - disabledCore = config.BidderInfo{Disabled: true} - disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + enabledCore = config.BidderInfo{Disabled: false} + enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} + enabledWhiteLabelOnly = config.BidderInfo{Disabled: false, WhiteLabelOnly: true} + disabledCore = config.BidderInfo{Disabled: true} + disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + disabledWhiteLabelOnly = config.BidderInfo{Disabled: true, WhiteLabelOnly: true} ) testCases := []struct { @@ -277,7 +330,7 @@ func TestPrepareBiddersResponseEnabledOnlyBaseOnly(t *testing.T) { }, { name: "alias-one-disabled", - givenBidders: config.BidderInfos{"a": enabledAlias}, + givenBidders: config.BidderInfos{"a": disabledAlias}, expected: `[]`, }, { @@ -285,10 +338,25 @@ func TestPrepareBiddersResponseEnabledOnlyBaseOnly(t *testing.T) { givenBidders: config.BidderInfos{"a": enabledAlias, "b": enabledAlias}, expected: `[]`, }, + { + name: "whitelabelonly-one-enabled", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-one-disabled", + givenBidders: config.BidderInfos{"a": disabledWhiteLabelOnly}, + expected: `[]`, + }, + { + name: "whitelabelonly-many", + givenBidders: config.BidderInfos{"a": enabledWhiteLabelOnly, "b": enabledWhiteLabelOnly}, + expected: `[]`, + }, { name: "mixed", - givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": enabledCore, "d": enabledAlias}, - expected: `["c"]`, + givenBidders: config.BidderInfos{"a": disabledCore, "b": disabledAlias, "c": disabledWhiteLabelOnly, "d": enabledCore, "e": enabledAlias, "f": enabledWhiteLabelOnly}, + expected: `["d"]`, }, } @@ -303,13 +371,15 @@ func TestPrepareBiddersResponseEnabledOnlyBaseOnly(t *testing.T) { func TestBiddersHandler(t *testing.T) { var ( - enabledCore = config.BidderInfo{Disabled: false} - enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} - disabledCore = config.BidderInfo{Disabled: true} - disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + enabledCore = config.BidderInfo{Disabled: false} + enabledAlias = config.BidderInfo{Disabled: false, AliasOf: "something"} + enabledWhiteLabelOnly = config.BidderInfo{Disabled: false, WhiteLabelOnly: true} + disabledCore = config.BidderInfo{Disabled: true} + disabledAlias = config.BidderInfo{Disabled: true, AliasOf: "something"} + disabledWhiteLabelOnly = config.BidderInfo{Disabled: true, WhiteLabelOnly: true} ) - bidders := config.BidderInfos{"a": enabledCore, "b": enabledAlias, "c": disabledCore, "d": disabledAlias} + bidders := config.BidderInfos{"a": enabledCore, "b": enabledAlias, "c": enabledWhiteLabelOnly, "d": disabledCore, "e": disabledAlias, "f": disabledWhiteLabelOnly} testCases := []struct { name string @@ -322,21 +392,21 @@ func TestBiddersHandler(t *testing.T) { name: "simple", givenURL: "/info/bidders", expectedStatus: http.StatusOK, - expectedBody: `["a","b","c","d"]`, + expectedBody: `["a","b","d","e"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { name: "enabledonly-false", givenURL: "/info/bidders?enabledonly=false", expectedStatus: http.StatusOK, - expectedBody: `["a","b","c","d"]`, + expectedBody: `["a","b","d","e"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { name: "enabledonly-false-caseinsensitive", givenURL: "/info/bidders?enabledonly=fAlSe", expectedStatus: http.StatusOK, - expectedBody: `["a","b","c","d"]`, + expectedBody: `["a","b","d","e"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { @@ -371,28 +441,28 @@ func TestBiddersHandler(t *testing.T) { name: "baseonly-false", givenURL: "/info/bidders?baseadaptersonly=false", expectedStatus: http.StatusOK, - expectedBody: `["a","b","c","d"]`, + expectedBody: `["a","b","d","e"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { name: "baseonly-false-caseinsensitive", givenURL: "/info/bidders?baseadaptersonly=fAlSe", expectedStatus: http.StatusOK, - expectedBody: `["a","b","c","d"]`, + expectedBody: `["a","b","d","e"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { name: "baseonly-true", givenURL: "/info/bidders?baseadaptersonly=true", expectedStatus: http.StatusOK, - expectedBody: `["a","c"]`, + expectedBody: `["a","d"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { name: "baseonly-true-caseinsensitive", givenURL: "/info/bidders?baseadaptersonly=TrUe", expectedStatus: http.StatusOK, - expectedBody: `["a","c"]`, + expectedBody: `["a","d"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { @@ -420,7 +490,7 @@ func TestBiddersHandler(t *testing.T) { name: "enabledonly-false-baseonly-true", givenURL: "/info/bidders?enabledonly=false&baseadaptersonly=true", expectedStatus: http.StatusOK, - expectedBody: `["a","c"]`, + expectedBody: `["a","d"]`, expectedHeaders: http.Header{"Content-Type": []string{"application/json"}}, }, { diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 68548d5b87..d18981a87c 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -1051,7 +1051,10 @@ func (deps *endpointDeps) validateAliases(aliases map[string]string) error { for alias, bidderName := range aliases { normalisedBidderName, _ := openrtb_ext.NormalizeBidderName(bidderName) coreBidderName := normalisedBidderName.String() - if _, isCoreBidderDisabled := deps.disabledBidders[coreBidderName]; isCoreBidderDisabled { + if disabledMessage, isCoreBidderDisabled := deps.disabledBidders[coreBidderName]; isCoreBidderDisabled { + if exchange.IsBidderDisabledDueToWhiteLabelOnly(disabledMessage) { + return fmt.Errorf("request.ext.prebid.aliases.%s refers to a bidder that cannot be aliased: %s", alias, bidderName) + } return fmt.Errorf("request.ext.prebid.aliases.%s refers to disabled bidder: %s", alias, bidderName) } diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index 1fc6e50346..1573de1fcb 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -5220,9 +5220,18 @@ func TestSetSeatNonBidRaw(t *testing.T) { } func TestValidateAliases(t *testing.T) { + // This test runs against a real list of bidders, so we must use real bidder names for core bidders, + // but can use test values for the alias names. deps := &endpointDeps{ - disabledBidders: map[string]string{"rubicon": "rubicon"}, - bidderMap: map[string]openrtb_ext.BidderName{"appnexus": openrtb_ext.BidderName("appnexus")}, + disabledBidders: map[string]string{ + "rubicon": "rubicon is disabled", + "appnexus": `Bidder "appnexus" can only be aliased and cannot be used directly.`, // exact wording needed to recognize white label only adapter error state + }, + bidderMap: map[string]openrtb_ext.BidderName{ + "appnexus": openrtb_ext.BidderName("appnexus"), + "rubicon": openrtb_ext.BidderName("rubicon"), + "openx": openrtb_ext.BidderName("openx"), + }, } testCases := []struct { @@ -5232,15 +5241,15 @@ func TestValidateAliases(t *testing.T) { expectedError error }{ { - description: "valid case", - aliases: map[string]string{"test": "appnexus"}, - expectedAliases: map[string]string{"test": "appnexus"}, + description: "valid", + aliases: map[string]string{"test": "openx"}, + expectedAliases: map[string]string{"test": "openx"}, expectedError: nil, }, { - description: "valid case - case insensitive", - aliases: map[string]string{"test": "Appnexus"}, - expectedAliases: map[string]string{"test": "appnexus"}, + description: "valid - case insensitive", + aliases: map[string]string{"test": "OpenX"}, + expectedAliases: map[string]string{"test": "openx"}, expectedError: nil, }, { @@ -5257,9 +5266,15 @@ func TestValidateAliases(t *testing.T) { }, { description: "alias name is coreBidder name", - aliases: map[string]string{"appnexus": "appnexus"}, + aliases: map[string]string{"openx": "openx"}, + expectedAliases: nil, + expectedError: errors.New("request.ext.prebid.aliases.openx defines a no-op alias. Choose a different alias, or remove this entry."), + }, + { + description: "white label only bidder cannot be aliased", + aliases: map[string]string{"test": "appnexus"}, expectedAliases: nil, - expectedError: errors.New("request.ext.prebid.aliases.appnexus defines a no-op alias. Choose a different alias, or remove this entry."), + expectedError: errors.New("request.ext.prebid.aliases.test refers to a bidder that cannot be aliased: appnexus"), }, } @@ -5269,7 +5284,7 @@ func TestValidateAliases(t *testing.T) { if err != nil { assert.Equal(t, testCase.expectedError, err) } else { - assert.ObjectsAreEqualValues(testCase.expectedAliases, map[string]string{"test": "appnexus"}) + assert.Equal(t, testCase.expectedAliases, testCase.aliases) } }) } diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 15385d35bb..b221a1adfb 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -3,6 +3,7 @@ package exchange import ( "fmt" "net/http" + "strings" "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/config" @@ -134,7 +135,10 @@ func mergeRemovedAndDisabledBidderWarningMessages(removed map[string]string, inf disabledBidders := removed for name, info := range infos { - if info.Disabled { + if info.WhiteLabelOnly { + msg := fmt.Sprintf(`Bidder "%s" can only be aliased and cannot be used directly.`, name) + disabledBidders[name] = msg + } else if info.Disabled { msg := fmt.Sprintf(`Bidder "%s" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`, name) disabledBidders[name] = msg } @@ -142,3 +146,7 @@ func mergeRemovedAndDisabledBidderWarningMessages(removed map[string]string, inf return disabledBidders } + +func IsBidderDisabledDueToWhiteLabelOnly(disabledMessage string) bool { + return strings.HasSuffix(disabledMessage, "can only be aliased and cannot be used directly.") +} diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go index e6da2f8e7c..9827758356 100644 --- a/exchange/adapter_util_test.go +++ b/exchange/adapter_util_test.go @@ -20,6 +20,7 @@ var ( falseValue = false infoEnabled = config.BidderInfo{Disabled: false} infoDisabled = config.BidderInfo{Disabled: true} + infoWhiteLabelOnly = config.BidderInfo{WhiteLabelOnly: true} multiformatDisabled = config.BidderInfo{ Disabled: false, OpenRTB: &config.OpenRTBInfo{ @@ -176,6 +177,14 @@ func TestBuildBidders(t *testing.T) { openrtb_ext.BidderRubicon: adapters.BuildInfoAwareBidder(rubiconBidder, infoEnabled), }, }, + { + description: "Success - Ignores WhiteLabelOnly", + bidderInfos: map[string]config.BidderInfo{"appnexus": infoWhiteLabelOnly, "rubicon": infoEnabled}, + builders: map[openrtb_ext.BidderName]adapters.Builder{openrtb_ext.BidderAppnexus: appnexusBuilder, openrtb_ext.BidderRubicon: rubiconBuilder}, + expectedBidders: map[openrtb_ext.BidderName]adapters.Bidder{ + openrtb_ext.BidderRubicon: adapters.BuildInfoAwareBidder(rubiconBidder, infoEnabled), + }, + }, } for _, test := range testCases { @@ -261,9 +270,14 @@ func TestGetActiveBidders(t *testing.T) { bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled}, expected: map[string]openrtb_ext.BidderName{}, }, + { + description: "WhiteLabelOnly", + bidderInfos: map[string]config.BidderInfo{"appnexus": infoWhiteLabelOnly}, + expected: map[string]openrtb_ext.BidderName{}, + }, { description: "Mixed", - bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled, "openx": infoEnabled}, + bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled, "openx": infoEnabled, "rubicon": infoWhiteLabelOnly}, expected: map[string]openrtb_ext.BidderName{"openx": openrtb_ext.BidderOpenx}, }, } @@ -293,6 +307,17 @@ func TestGetDisabledBidderWarningMessages(t *testing.T) { require.Contains(t, result, "bidderA") assert.Equal(t, result["bidderA"], `Bidder "bidderA" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`) }) + + t.Run("removed-and-whitelabelonly", func(t *testing.T) { + result := GetDisabledBidderWarningMessages(map[string]config.BidderInfo{"bidderA": infoWhiteLabelOnly}) + + // test proper construction by verifying one expected bidder is in the list with the whitelabelonly bidder + require.Contains(t, result, "groupm") + assert.Equal(t, result["groupm"], `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`) + + require.Contains(t, result, "bidderA") + assert.Equal(t, result["bidderA"], `Bidder "bidderA" can only be aliased and cannot be used directly.`) + }) } func TestMergeRemovedAndDisabledBidderWarningMessages(t *testing.T) { @@ -326,11 +351,17 @@ func TestMergeRemovedAndDisabledBidderWarningMessages(t *testing.T) { givenBidderInfos: map[string]config.BidderInfo{"bidderA": infoDisabled}, expected: map[string]string{"bidderA": `Bidder "bidderA" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`}, }, + { + name: "whitelabelonly", + givenRemoved: map[string]string{}, + givenBidderInfos: map[string]config.BidderInfo{"bidderA": infoWhiteLabelOnly}, + expected: map[string]string{"bidderA": `Bidder "bidderA" can only be aliased and cannot be used directly.`}, + }, { name: "mixed", givenRemoved: map[string]string{"bidderA": `Bidder A Message`}, - givenBidderInfos: map[string]config.BidderInfo{"bidderB": infoEnabled, "bidderC": infoDisabled}, - expected: map[string]string{"bidderA": `Bidder A Message`, "bidderC": `Bidder "bidderC" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`}, + givenBidderInfos: map[string]config.BidderInfo{"bidderB": infoEnabled, "bidderC": infoDisabled, "bidderD": infoWhiteLabelOnly}, + expected: map[string]string{"bidderA": `Bidder A Message`, "bidderC": `Bidder "bidderC" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`, "bidderD": `Bidder "bidderD" can only be aliased and cannot be used directly.`}, }, } @@ -342,6 +373,42 @@ func TestMergeRemovedAndDisabledBidderWarningMessages(t *testing.T) { } } +func TestIsBidderDisabledDueToWhiteLabelOnly(t *testing.T) { + testCases := []struct { + name string + message string + expected bool + }{ + { + name: "empty", + message: "", + expected: false, + }, + { + name: "whitelabelonly", + message: `Bidder "test" can only be aliased and cannot be used directly.`, + expected: true, + }, + { + name: "disabled", + message: `Bidder "test" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`, + expected: false, + }, + { + name: "removed", + message: `Bidder "test" is no longer available in Prebid Server. Please update your configuration.`, + expected: false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := IsBidderDisabledDueToWhiteLabelOnly(test.message) + assert.Equal(t, test.expected, result) + }) + } +} + type fakeBidder struct { name string } diff --git a/usersync/syncersbuilder.go b/usersync/syncersbuilder.go index b79cdf48c7..1127989e9d 100644 --- a/usersync/syncersbuilder.go +++ b/usersync/syncersbuilder.go @@ -80,7 +80,7 @@ func BuildSyncers(hostConfig *config.Configuration, bidderInfos config.BidderInf } func shouldCreateSyncer(cfg config.BidderInfo) bool { - if cfg.Disabled { + if !cfg.IsEnabled() { return false } diff --git a/usersync/syncersbuilder_test.go b/usersync/syncersbuilder_test.go index 041c83a7b5..d7026543f4 100644 --- a/usersync/syncersbuilder_test.go +++ b/usersync/syncersbuilder_test.go @@ -269,6 +269,21 @@ func TestShouldCreateSyncer(t *testing.T) { given: config.BidderInfo{Disabled: true, Syncer: &config.Syncer{SupportCORS: &anyCORS}}, expected: false, }, + { + description: "WhiteLabelOnly, No Syncer", + given: config.BidderInfo{WhiteLabelOnly: true, Syncer: nil}, + expected: false, + }, + { + description: "WhiteLabelOnly, Syncer", + given: config.BidderInfo{WhiteLabelOnly: true, Syncer: &config.Syncer{Key: "anyKey"}}, + expected: false, + }, + { + description: "WhiteLabelOnly, Syncer - Fully Loaded", + given: config.BidderInfo{WhiteLabelOnly: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}}, + expected: false, + }, } for _, test := range testCases { From 25cd15f8910011bebda9823a3763e892d0df51a3 Mon Sep 17 00:00:00 2001 From: Veronika Solovei Date: Tue, 12 Aug 2025 10:10:00 -0700 Subject: [PATCH 055/272] Rules Engine Module: Result functions fix (#4451) --- .../processedauctionrequest_mutations.go | 59 ++- .../processedauctionrequest_mutations_test.go | 201 +++++++--- modules/prebid/rulesengine/cache_entry.go | 17 +- .../prebid/rulesengine/cache_entry_test.go | 39 +- .../rulesengine/hook_processed_auction.go | 27 +- .../hook_processed_auction_test.go | 22 +- .../prebid/rulesengine/result_functions.go | 87 +---- .../rulesengine/result_functions_test.go | 363 +----------------- .../prebid/rulesengine/tree_builder_test.go | 13 +- modules/prebid/rulesengine/tree_test.go | 27 +- 10 files changed, 310 insertions(+), 545 deletions(-) diff --git a/hooks/hookstage/processedauctionrequest_mutations.go b/hooks/hookstage/processedauctionrequest_mutations.go index 054e4466f4..9cd9c64573 100644 --- a/hooks/hookstage/processedauctionrequest_mutations.go +++ b/hooks/hookstage/processedauctionrequest_mutations.go @@ -32,25 +32,62 @@ func (c ChangeSetProcessedAuctionRequest[T]) castPayload(p T) (*openrtb_ext.Requ return nil, errors.New("failed to cast ProcessedAuctionRequestPayload") } -func (c ChangeBidders[T]) Update(impIdToBidders map[string]map[string]json.RawMessage) { +func (c ChangeBidders[T]) Add(finalBidders map[string]struct{}) { c.changeSetProcessedAuctionRequest.changeSet.AddMutation(func(p T) (T, error) { bidRequest, err := c.changeSetProcessedAuctionRequest.castPayload(p) if err == nil { for _, impWrapper := range bidRequest.GetImp() { - if impBidders, ok := impIdToBidders[impWrapper.ID]; ok { - impExt, impExtErr := impWrapper.GetImpExt() - if err != nil { - return p, impExtErr + + impExt, impExtErr := impWrapper.GetImpExt() + if err != nil { + return p, impExtErr + } + impPrebid := impExt.GetPrebid() + if impPrebid == nil { + impPrebid = &openrtb_ext.ExtImpPrebid{} + } + resBidders := make(map[string]json.RawMessage) + for impBidder, bidderParams := range impPrebid.Bidder { + if _, exists := finalBidders[impBidder]; exists { + resBidders[impBidder] = bidderParams } - impPrebid := impExt.GetPrebid() - if impPrebid == nil { - impPrebid = &openrtb_ext.ExtImpPrebid{} + } + impPrebid.Bidder = resBidders + impExt.SetPrebid(impPrebid) + + } + } + return p, err + }, MutationAdd, "bidrequest", "imp", "ext", "prebid", "bidders") +} + +func (c ChangeBidders[T]) Delete(biddersToDelete map[string]struct{}) { + c.changeSetProcessedAuctionRequest.changeSet.AddMutation(func(p T) (T, error) { + bidRequest, err := c.changeSetProcessedAuctionRequest.castPayload(p) + if err == nil { + for _, impWrapper := range bidRequest.GetImp() { + impExt, impExtErr := impWrapper.GetImpExt() + if err != nil { + return p, impExtErr + } + impPrebid := impExt.GetPrebid() + if impPrebid == nil { + return p, nil + } + + newImpBidders := make(map[string]json.RawMessage) + + for bidderName, bidderData := range impPrebid.Bidder { + if _, exists := biddersToDelete[bidderName]; !exists { + newImpBidders[bidderName] = bidderData } - impPrebid.Bidder = impBidders - impExt.SetPrebid(impPrebid) } + + impPrebid.Bidder = newImpBidders + impExt.SetPrebid(impPrebid) + } } return p, err - }, MutationUpdate, "bidrequest", "imp", "ext", "prebid", "bidders") + }, MutationDelete, "bidrequest", "imp", "ext", "prebid", "bidders") } diff --git a/hooks/hookstage/processedauctionrequest_mutations_test.go b/hooks/hookstage/processedauctionrequest_mutations_test.go index e68dec62c9..bf7616a6d3 100644 --- a/hooks/hookstage/processedauctionrequest_mutations_test.go +++ b/hooks/hookstage/processedauctionrequest_mutations_test.go @@ -2,99 +2,208 @@ package hookstage import ( "encoding/json" + "testing" + "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" - "testing" ) -func TestUpdatePrebidBidders(t *testing.T) { +func TestAddPrebidBidders(t *testing.T) { tests := []struct { - name string - bidRequest *openrtb2.BidRequest - impIdToBidders map[string]map[string]json.RawMessage - extImpPrebid *openrtb_ext.ExtImpPrebid - expectErr bool - expectEmptyImps bool - expectData openrtb_ext.ExtImpPrebid + name string + bidRequest *openrtb2.BidRequest + allowedBidders []map[string]struct{} // list to allow multiple mutations + extImpPrebid *openrtb_ext.ExtImpPrebid + expectData openrtb_ext.ExtImpPrebid }{ { - name: "nil-req-imp", - bidRequest: &openrtb2.BidRequest{Imp: nil}, - impIdToBidders: map[string]map[string]json.RawMessage{"ImpA": {"bidderA": json.RawMessage(`{"param1": "value1"}`)}}, + name: "none-allowed-bidder-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, - expectEmptyImps: true, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{}}, }, { - name: "empty-req-imp", - bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{}}, - impIdToBidders: map[string]map[string]json.RawMessage{"ImpA": {"bidderA": json.RawMessage(`{"param1": "value1"}`)}}, + name: "one-allowed-bidder-one-imp-bidder-one-mutation-match", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderB": {}}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ - "bidderA": json.RawMessage(`{"paramA": "valueA"}`), "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, - expectEmptyImps: true, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, }, { - name: "nil-req-imp-ext-prebid", - impIdToBidders: map[string]map[string]json.RawMessage{"ImpA": {"bidderA": json.RawMessage(`{"param1": "value1"}`)}}, - extImpPrebid: nil, - expectErr: false, + name: "one-allowed-bidder-one-imp-bidder-one-mutation-different", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderA": {}}}, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{}}, + }, + { + name: "one-allowed-bidder-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderB": {}}}, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ - "bidderA": json.RawMessage(`{"param1": "value1"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + }, + { + name: "two-allowed-bidders-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{ + {"bidderA": {}, "bidderB": {}}, // one mutation for two bidders }, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + }, + { + name: "two-imp-bidders-two-mutations-override-all", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{ + {"bidderA": {}}, // first mutation for bidderA + {"bidderB": {}}, // second mutation for bidderB }, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{}}, }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + br := &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}} + if tt.bidRequest != nil { + br = tt.bidRequest + } + brw := openrtb_ext.RequestWrapper{BidRequest: br} + impWrapperArr := brw.GetImp() + + if len(impWrapperArr) > 0 { + impExt, err := brw.GetImp()[0].GetImpExt() + assert.NoError(t, err) + impExt.SetPrebid(tt.extImpPrebid) + } + + payload := ProcessedAuctionRequestPayload{Request: &brw} + + cpar := ChangeSetProcessedAuctionRequest[ProcessedAuctionRequestPayload]{ + changeSet: &ChangeSet[ProcessedAuctionRequestPayload]{}, + } + + for _, allowedBidders := range tt.allowedBidders { + cpar.Bidders().Add(allowedBidders) + } + + for _, mut := range cpar.changeSet.Mutations() { + _, err := mut.Apply(payload) + assert.NoError(t, err) + } + + impExtRes, err := payload.Request.GetImp()[0].GetImpExt() + assert.NoError(t, err) + assert.Equal(t, &tt.expectData, impExtRes.GetPrebid(), "Bidder data should match expected") + + }) + } + +} + +func TestDeletePrebidBidders(t *testing.T) { + tests := []struct { + name string + bidRequest *openrtb2.BidRequest + allowedBidders []map[string]struct{} // list to allow multiple mutations + extImpPrebid *openrtb_ext.ExtImpPrebid + expectData openrtb_ext.ExtImpPrebid + }{ + { - name: "one-req-imp-with-multiple-bidders-update-existing-bidder", - impIdToBidders: map[string]map[string]json.RawMessage{"ImpA": {"bidderA": json.RawMessage(`{"param1": "value1"}`)}}, + name: "none-allowed-bidder-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ - "bidderA": json.RawMessage(`{"param1": "value1"}`), + "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, }, { - name: "one-req-imp-with-multiple-bidders-update-new-bidder", - impIdToBidders: map[string]map[string]json.RawMessage{"ImpA": {"bidderC": json.RawMessage(`{"param1": "value1"}`)}}, + name: "one-allowed-bidder-one-imp-bidder-one-mutation-match", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderB": {}}}, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + }}, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{}}, + }, + { + name: "one-allowed-bidder-one-imp-bidder-one-mutation-different", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderA": {}}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ - "bidderA": json.RawMessage(`{"paramA": "valueA"}`), "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ - "bidderC": json.RawMessage(`{"param1": "value1"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, }, { - name: "empty-imp-map", - impIdToBidders: map[string]map[string]json.RawMessage{}, + name: "one-allowed-bidder-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderB": {}}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), }}, }, { - name: "one-req-imp-with-one-bidder-imp-not-found", - impIdToBidders: map[string]map[string]json.RawMessage{"ImpABC": {"bidderC": json.RawMessage(`{"param1": "value1"}`)}}, + name: "two-allowed-bidders-two-imp-bidders-one-mutation", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderA": {}, "bidderB": {}}}, extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), }}, - expectErr: false, - expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{}}, + }, + { + name: "two-imp-bidders-two-mutations-delete-two", + bidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "ImpA"}}}, + allowedBidders: []map[string]struct{}{{"bidderA": {}}, {"bidderB": {}}}, + extImpPrebid: &openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ "bidderA": json.RawMessage(`{"paramA": "valueA"}`), + "bidderB": json.RawMessage(`{"paramB": "valueB"}`), + "bidderC": json.RawMessage(`{"paramC": "valueC"}`), + }}, + expectData: openrtb_ext.ExtImpPrebid{Bidder: map[string]json.RawMessage{ + "bidderC": json.RawMessage(`{"paramC": "valueC"}`), }}, }, } @@ -119,18 +228,16 @@ func TestUpdatePrebidBidders(t *testing.T) { cpar := ChangeSetProcessedAuctionRequest[ProcessedAuctionRequestPayload]{ changeSet: &ChangeSet[ProcessedAuctionRequestPayload]{}, } - cpar.Bidders().Update(tt.impIdToBidders) + + for _, allowedBidders := range tt.allowedBidders { + cpar.Bidders().Delete(allowedBidders) + } for _, mut := range cpar.changeSet.Mutations() { _, err := mut.Apply(payload) assert.NoError(t, err) } - if tt.expectEmptyImps { - assert.Empty(t, payload.Request.GetImp(), "Expected no imps in the request") - return - } - impExtRes, err := payload.Request.GetImp()[0].GetImpExt() assert.NoError(t, err) assert.Equal(t, &tt.expectData, impExtRes.GetPrebid(), "Bidder data should match expected") diff --git a/modules/prebid/rulesengine/cache_entry.go b/modules/prebid/rulesengine/cache_entry.go index 3bde0fc592..8774023c99 100644 --- a/modules/prebid/rulesengine/cache_entry.go +++ b/modules/prebid/rulesengine/cache_entry.go @@ -8,7 +8,6 @@ import ( "time" "github.com/prebid/prebid-server/v3/hooks" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/rules" @@ -20,7 +19,7 @@ type cacheEntry struct { enabled bool timestamp time.Time hashedConfig hash - ruleSetsForProcessedAuctionRequestStage []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]] + ruleSetsForProcessedAuctionRequestStage []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult] } type cacheRuleSet[T1 any, T2 any] struct { name string @@ -71,19 +70,19 @@ func NewCacheEntry(cfg *config.PbRulesEngine, cfgRaw *json.RawMessage) (cacheEnt // createCacheRuleSet creates a new cache rule set for the given configuration // It builds the tree structures for the model groups and stores them in the cache rule set -func createCacheRuleSet(cfg *config.RuleSet) (cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]], error) { +func createCacheRuleSet(cfg *config.RuleSet) (cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult], error) { if cfg == nil { - return cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, errors.New("no rules engine configuration provided") + return cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, errors.New("no rules engine configuration provided") } - crs := cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + crs := cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ name: cfg.Name, - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, } for _, modelGroup := range cfg.ModelGroups { - tree, err := rules.NewTree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]( - &treeBuilder[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + tree, err := rules.NewTree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]( + &treeBuilder[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ Config: modelGroup, SchemaFuncFactory: rules.NewRequestSchemaFunction, ResultFuncFactory: NewProcessedAuctionRequestResultFunction, @@ -93,7 +92,7 @@ func createCacheRuleSet(cfg *config.RuleSet) (cacheRuleSet[openrtb_ext.RequestWr return crs, err } - cmg := cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + cmg := cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ weight: modelGroup.Weight, version: modelGroup.Version, analyticsKey: modelGroup.AnalyticsKey, diff --git a/modules/prebid/rulesengine/cache_entry_test.go b/modules/prebid/rulesengine/cache_entry_test.go index 9109d67b94..c06629de09 100644 --- a/modules/prebid/rulesengine/cache_entry_test.go +++ b/modules/prebid/rulesengine/cache_entry_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/prebid/prebid-server/v3/hooks" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/rules" @@ -180,13 +179,13 @@ func TestCreateCacheRuleSet(t *testing.T) { testCases := []struct { name string in *config.RuleSet - expectedRuleSet cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]] + expectedRuleSet cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult] expectedErr error }{ { name: "nil-ruleset-config", in: nil, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, expectedErr: errors.New("no rules engine configuration provided"), }, { @@ -194,7 +193,7 @@ func TestCreateCacheRuleSet(t *testing.T) { in: &config.RuleSet{ ModelGroups: nil, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}}, + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}}, expectedErr: nil, }, { @@ -202,7 +201,7 @@ func TestCreateCacheRuleSet(t *testing.T) { in: &config.RuleSet{ ModelGroups: []config.ModelGroup{}, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}}, + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}}, expectedErr: nil, }, { @@ -218,7 +217,7 @@ func TestCreateCacheRuleSet(t *testing.T) { }, }, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}}, + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}}, expectedErr: errors.New("result function unknownResultFunction was not created"), }, { @@ -235,12 +234,12 @@ func TestCreateCacheRuleSet(t *testing.T) { }, }, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { - tree: rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, - DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + tree: rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, + DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ &ExcludeBidders{ Args: config.ResultFuncParams{ Bidders: []string{"bidderA"}, @@ -273,7 +272,7 @@ func TestCreateCacheRuleSet(t *testing.T) { }, }, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}}, + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}}, expectedErr: errors.New("result function unknownResultFunction was not created"), }, { @@ -298,12 +297,12 @@ func TestCreateCacheRuleSet(t *testing.T) { }, }, }, - expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + expectedRuleSet: cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { - tree: rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, - DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + tree: rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, + DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ &ExcludeBidders{ Args: config.ResultFuncParams{ Bidders: []string{"bidderFoo"}, @@ -314,9 +313,9 @@ func TestCreateCacheRuleSet(t *testing.T) { }, }, { - tree: rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, - DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + tree: rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, + DefaultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ &IncludeBidders{ Args: config.ResultFuncParams{ Bidders: []string{"bidderBar"}, diff --git a/modules/prebid/rulesengine/hook_processed_auction.go b/modules/prebid/rulesengine/hook_processed_auction.go index e799f238e2..144b72a943 100644 --- a/modules/prebid/rulesengine/hook_processed_auction.go +++ b/modules/prebid/rulesengine/hook_processed_auction.go @@ -9,31 +9,42 @@ import ( ) type RequestWrapper = openrtb_ext.RequestWrapper -type ProcessedAuctionHookResult = hs.HookResult[hs.ProcessedAuctionRequestPayload] type ModelGroup = cacheModelGroup[RequestWrapper, ProcessedAuctionHookResult] +type ProcessedAuctionHookResult struct { + HookResult hs.HookResult[hs.ProcessedAuctionRequestPayload] + AllowedBidders map[string]struct{} +} + func handleProcessedAuctionHook( - ruleSets []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]], + ruleSets []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult], payload hs.ProcessedAuctionRequestPayload) (hs.HookResult[hs.ProcessedAuctionRequestPayload], error) { - result := hs.HookResult[hs.ProcessedAuctionRequestPayload]{ - ChangeSet: hs.ChangeSet[hs.ProcessedAuctionRequestPayload]{}, + result := ProcessedAuctionHookResult{ + HookResult: hs.HookResult[hs.ProcessedAuctionRequestPayload]{ + ChangeSet: hs.ChangeSet[hs.ProcessedAuctionRequestPayload]{}, + }, + AllowedBidders: make(map[string]struct{}), } for _, ruleSet := range ruleSets { selectedGroup, err := selectModelGroup(ruleSet.modelGroups, randomutil.RandomNumberGenerator{}) if err != nil { - result.Errors = append(result.Errors, fmt.Sprintf("failed to select model group: %s", err)) + result.HookResult.Errors = append(result.HookResult.Errors, fmt.Sprintf("failed to select model group: %s", err)) continue } - if err := selectedGroup.tree.Run(payload.Request, &result); err != nil { + if err = selectedGroup.tree.Run(payload.Request, &result); err != nil { //TODO: classify errors as warnings or errors - result.Errors = append(result.Errors, err.Error()) + result.HookResult.Errors = append(result.HookResult.Errors, err.Error()) + } + + if len(result.AllowedBidders) > 0 { + result.HookResult.ChangeSet.ProcessedAuctionRequest().Bidders().Add(result.AllowedBidders) } } - return result, nil + return result.HookResult, nil } func selectModelGroup(modelGroups []ModelGroup, rg randomutil.RandomGenerator) (ModelGroup, error) { diff --git a/modules/prebid/rulesengine/hook_processed_auction_test.go b/modules/prebid/rulesengine/hook_processed_auction_test.go index 1e40d60dbf..9cc5fc7f8e 100644 --- a/modules/prebid/rulesengine/hook_processed_auction_test.go +++ b/modules/prebid/rulesengine/hook_processed_auction_test.go @@ -13,26 +13,26 @@ import ( func TestHandleProcessedAuctionHook(t *testing.T) { tests := []struct { name string - ruleSets []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]] + ruleSets []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult] payload hs.ProcessedAuctionRequestPayload expectedError bool expectedResult hs.HookResult[hs.ProcessedAuctionRequestPayload] }{ { name: "empty-rule-sets", - ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, payload: hs.ProcessedAuctionRequestPayload{}, expectedError: false, expectedResult: hs.HookResult[hs.ProcessedAuctionRequestPayload]{}, }, { name: "single-rule-set-with-valid-model-group-and-empty-rule-tree", - ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { weight: 100, - tree: rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + tree: rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, }, }, }, @@ -45,9 +45,9 @@ func TestHandleProcessedAuctionHook(t *testing.T) { }, { name: "failed-to-select-model-group", - ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, }, }, payload: hs.ProcessedAuctionRequestPayload{}, @@ -58,13 +58,13 @@ func TestHandleProcessedAuctionHook(t *testing.T) { }, { name: "single-rule-set-with-valid-model-group-and-valid-rule-tree", - ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + ruleSets: []cacheRuleSet[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { - modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + modelGroups: []cacheModelGroup[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ { weight: 100, - tree: rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + tree: rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, }, }, }, diff --git a/modules/prebid/rulesengine/result_functions.go b/modules/prebid/rulesengine/result_functions.go index ddd61b47c7..64fe23bc4a 100644 --- a/modules/prebid/rulesengine/result_functions.go +++ b/modules/prebid/rulesengine/result_functions.go @@ -4,17 +4,15 @@ import ( "encoding/json" "errors" "fmt" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "slices" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/rules" "github.com/prebid/prebid-server/v3/util/jsonutil" ) // ProcessedAuctionResultFunc is a type alias for a result function that runs in the processed auction request stage. -type ProcessedAuctionResultFunc = rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]] +type ProcessedAuctionResultFunc = rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult] const ( ExcludeBiddersName = "excludeBidders" @@ -62,18 +60,13 @@ type ExcludeBidders struct { } // Call is a method that applies the changes specified in the ExcludeBidders instance to the provided ChangeSet by creating a mutation. -func (eb *ExcludeBidders) Call(req *openrtb_ext.RequestWrapper, result *hs.HookResult[hs.ProcessedAuctionRequestPayload], meta rules.ResultFunctionMeta) error { - // create a change set which captures the changes we want to apply - // this function should NOT perform any modifications to the request - - // build map[impId] to map [bidder] to bidder params - impIdToBidders, err := buildExcludeBidders(req, eb.Args.Bidders) - if err != nil { - return err +func (eb *ExcludeBidders) Call(req *openrtb_ext.RequestWrapper, result *ProcessedAuctionHookResult, meta rules.ResultFunctionMeta) error { + excludedBidders := make(map[string]struct{}) + for _, bidderName := range eb.Args.Bidders { + excludedBidders[bidderName] = struct{}{} // Ensure the bidder is included in the allowed bidders } - result.ChangeSet.ProcessedAuctionRequest().Bidders().Update(impIdToBidders) - + result.HookResult.ChangeSet.ProcessedAuctionRequest().Bidders().Delete(excludedBidders) return nil } @@ -103,73 +96,13 @@ type IncludeBidders struct { } // Call is a method that applies the changes specified in the IncludeBidders instance to the provided ChangeSet by creating a mutation. -func (ib *IncludeBidders) Call(req *openrtb_ext.RequestWrapper, result *hs.HookResult[hs.ProcessedAuctionRequestPayload], meta rules.ResultFunctionMeta) error { - // create a change set which captures the changes we want to apply - // this function should NOT perform any modifications to the request - - // build map[impId] to map [bidder] to bidder params - impIdToBidders, err := buildIncludeBidders(req, ib.Args.Bidders) - if err != nil { - return err +func (ib *IncludeBidders) Call(req *openrtb_ext.RequestWrapper, result *ProcessedAuctionHookResult, meta rules.ResultFunctionMeta) error { + for _, bidderName := range ib.Args.Bidders { + result.AllowedBidders[bidderName] = struct{}{} // Ensure the bidder is included in the allowed bidders } - - result.ChangeSet.ProcessedAuctionRequest().Bidders().Update(impIdToBidders) - return nil } func (ib *IncludeBidders) Name() string { return IncludeBiddersName } - -func buildIncludeBidders(req *openrtb_ext.RequestWrapper, argBidders []string) (map[string]map[string]json.RawMessage, error) { - impIdToBidders := make(map[string]map[string]json.RawMessage) - for _, impWrapper := range req.GetImp() { - impExt, impExtErr := impWrapper.GetImpExt() - if impExtErr != nil { - return impIdToBidders, impExtErr - } - impPrebid := impExt.GetPrebid() - if impPrebid == nil { - return nil, fmt.Errorf("impExt for imp %s does not contain prebid extension", impWrapper.ID) - } - impBidders := impPrebid.Bidder - - resultImpBidders := make(map[string]json.RawMessage) - for _, bidder := range argBidders { - // add only bidders from argBidders - if _, ok := impBidders[bidder]; ok { - resultImpBidders[bidder] = impBidders[bidder] - } - } - impIdToBidders[impWrapper.ID] = resultImpBidders - } - return impIdToBidders, nil -} - -func buildExcludeBidders(req *openrtb_ext.RequestWrapper, argBidders []string) (map[string]map[string]json.RawMessage, error) { - impIdToBidders := make(map[string]map[string]json.RawMessage) - for _, impWrapper := range req.GetImp() { - impExt, impExtErr := impWrapper.GetImpExt() - if impExtErr != nil { - return impIdToBidders, impExtErr - } - impPrebid := impExt.GetPrebid() - if impPrebid == nil { - return nil, fmt.Errorf("impExt for imp %s does not contain prebid extension", impWrapper.ID) - } - impBidders := impPrebid.Bidder - - resultImpBidders := make(map[string]json.RawMessage) - - for bidderName, bidderData := range impBidders { - // do not add bidders from argBidders - if contains := slices.Contains(argBidders, bidderName); !contains { - resultImpBidders[bidderName] = bidderData - } - } - - impIdToBidders[impWrapper.ID] = resultImpBidders - } - return impIdToBidders, nil -} diff --git a/modules/prebid/rulesengine/result_functions_test.go b/modules/prebid/rulesengine/result_functions_test.go index d81612ca66..1b78471ed1 100644 --- a/modules/prebid/rulesengine/result_functions_test.go +++ b/modules/prebid/rulesengine/result_functions_test.go @@ -2,13 +2,14 @@ package rulesengine import ( "encoding/json" + "testing" + "github.com/prebid/openrtb/v20/openrtb2" hs "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/rules" "github.com/stretchr/testify/assert" - "testing" ) func TestNewProcessedAuctionRequestResultFunction(t *testing.T) { @@ -108,16 +109,20 @@ func TestExcludeBiddersCall(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { eb := &ExcludeBidders{Args: config.ResultFuncParams{Bidders: tt.argBidders}} - result := &hs.HookResult[hs.ProcessedAuctionRequestPayload]{ + hookResult := hs.HookResult[hs.ProcessedAuctionRequestPayload]{ ChangeSet: hs.ChangeSet[hs.ProcessedAuctionRequestPayload]{}, } + result := &ProcessedAuctionHookResult{ + HookResult: hookResult, + AllowedBidders: make(map[string]struct{}), + } err := eb.Call(tt.req, result, rules.ResultFunctionMeta{}) assert.NoError(t, err) - assert.NotEmptyf(t, result.ChangeSet, "change set is empty") - assert.Len(t, result.ChangeSet.Mutations(), 1) - assert.Equal(t, hs.MutationUpdate, result.ChangeSet.Mutations()[0].Type()) + assert.NotEmptyf(t, result.HookResult.ChangeSet, "change set is empty") + assert.Len(t, result.HookResult.ChangeSet.Mutations(), 1) + assert.Equal(t, hs.MutationDelete, result.HookResult.ChangeSet.Mutations()[0].Type()) }) } @@ -166,272 +171,21 @@ func TestIncludeBiddersCall(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ib := &IncludeBidders{Args: config.ResultFuncParams{Bidders: tt.argBidders}} - result := &hs.HookResult[hs.ProcessedAuctionRequestPayload]{ + hookResult := hs.HookResult[hs.ProcessedAuctionRequestPayload]{ ChangeSet: hs.ChangeSet[hs.ProcessedAuctionRequestPayload]{}, } - err := ib.Call(tt.req, result, rules.ResultFunctionMeta{}) - - assert.NoError(t, err) - assert.NotEmptyf(t, result.ChangeSet, "change set is empty") - assert.Len(t, result.ChangeSet.Mutations(), 1) - assert.Equal(t, hs.MutationUpdate, result.ChangeSet.Mutations()[0].Type()) - }) - } -} - -func TestBuildIncludeBidders(t *testing.T) { - tests := []struct { - name string - argBidders []string - req *openrtb_ext.RequestWrapper - expected map[string]map[string]json.RawMessage - expectErr bool - }{ - { - name: "include_valid_bidders", - argBidders: []string{"bidder1", "bidder2"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1", "bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder1": json.RawMessage(`{}`), - "bidder2": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "no_matching_bidders", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1", "bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{"imp1": {}}, - expectErr: false, - }, - { - name: "req-imp-is-nil", - argBidders: []string{"bidder4"}, - req: &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}}, - expected: map[string]map[string]json.RawMessage{}, - expectErr: false, - }, - { - name: "req-imp-is-empty", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithEmptyImp(t), - expected: map[string]map[string]json.RawMessage{}, - expectErr: false, - }, - { - name: "req-imp-ext-is-nil", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithImpExtNil(t), - expectErr: true, - }, - { - name: "req-imp-ext-error", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithInvalidImpExt(t), - expectErr: true, - }, - { - name: "req-imp-ext-prebid-is-nil", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithImpExtPrebidNil(t), - expectErr: true, - }, - { - name: "include-one-bidder-already-in-req", - argBidders: []string{"bidder1"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder1": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "include-one-bidder-not-in-req", - argBidders: []string{"bidder2"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1"}), - expected: map[string]map[string]json.RawMessage{"imp1": {}}, - expectErr: false, - }, - { - name: "include-multiple-bidders-not-in-req", - argBidders: []string{"bidder1", "bidder2", "bidder3"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder4"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": {}, - }, - expectErr: false, - }, - { - name: "include-one-bidder-in-req-and-one-not-in-req", - argBidders: []string{"bidder1", "bidder2"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder2": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "multiple-imps", - argBidders: []string{"bidder1", "bidder2"}, - req: mockRequestWrapperWithBMultipleImpsWithBidders(t, []string{"bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder2": json.RawMessage(`{}`), - }, - "imp2": { - "bidder2": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := buildIncludeBidders(tt.req, tt.argBidders) - if tt.expectErr { - assert.Error(t, err, "expected error but got nil") - } else { - assert.NoError(t, err, "unexpected error") - assert.True(t, compareMaps(result, tt.expected), "bidders to include do not match") + result := &ProcessedAuctionHookResult{ + HookResult: hookResult, + AllowedBidders: make(map[string]struct{}), } - }) - } -} -func TestBuildExcludeBidders(t *testing.T) { - tests := []struct { - name string - argBidders []string - req *openrtb_ext.RequestWrapper - expected map[string]map[string]json.RawMessage - expectErr bool - }{ - { - name: "exclude_valid_bidders", - argBidders: []string{"bidder1"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1", "bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder2": json.RawMessage(`{}`), - "bidder3": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "exclude_all_bidders", - argBidders: []string{"bidder1", "bidder2", "bidder3"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1", "bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{"imp1": {}}, - expectErr: false, - }, - { - name: "req-imp-is-nil", - argBidders: []string{"bidder4"}, - req: &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}}, - expected: map[string]map[string]json.RawMessage{}, - expectErr: false, - }, - { - name: "req-imp-is-empty", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithEmptyImp(t), - expected: map[string]map[string]json.RawMessage{}, - expectErr: false, - }, - { - name: "req-imp-ext-is-nil", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithImpExtNil(t), - expectErr: true, - }, - { - name: "req-imp-ext-error", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithInvalidImpExt(t), - expectErr: true, - }, - { - name: "req-imp-ext-prebid-is-nil", - argBidders: []string{"bidder4"}, - req: mockRequestWrapperWithImpExtPrebidNil(t), - expectErr: true, - }, - { - name: "exclude-one-bidder-already-in-req", - argBidders: []string{"bidder1"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": {}, - }, - expectErr: false, - }, - { - name: "exclude-one-bidder-not-in-req", - argBidders: []string{"bidder2"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder1"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder1": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "exclude-multiple-bidders-not-in-req", - argBidders: []string{"bidder1", "bidder2", "bidder3"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder4"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder4": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "exclude-one-bidder-in-req-and-one-not-in-req", - argBidders: []string{"bidder1", "bidder2"}, - req: mockRequestWrapperWithBidders(t, []string{"bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder3": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - { - name: "multiple-imps", - argBidders: []string{"bidder1", "bidder2"}, - req: mockRequestWrapperWithBMultipleImpsWithBidders(t, []string{"bidder2", "bidder3"}), - expected: map[string]map[string]json.RawMessage{ - "imp1": { - "bidder3": json.RawMessage(`{}`), - }, - "imp2": { - "bidder3": json.RawMessage(`{}`), - }, - }, - expectErr: false, - }, - } + err := ib.Call(tt.req, result, rules.ResultFunctionMeta{}) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := buildExcludeBidders(tt.req, tt.argBidders) - if tt.expectErr { - assert.Error(t, err, "expected error but got nil") - } else { - assert.NoError(t, err, "unexpected error") - assert.True(t, compareMaps(result, tt.expected), "bidders to exclude do not match") - } + assert.NoError(t, err) + assert.Emptyf(t, result.HookResult.ChangeSet, "change set is empty") + assert.Len(t, result.HookResult.ChangeSet.Mutations(), 0) + assert.Len(t, result.AllowedBidders, len(tt.argBidders)) }) } } @@ -453,82 +207,3 @@ func mockRequestWrapperWithBidders(t *testing.T, bidders []string) *openrtb_ext. return rw } - -func mockRequestWrapperWithBMultipleImpsWithBidders(t *testing.T, bidders []string) *openrtb_ext.RequestWrapper { - //---imp1--- - imp1Wrapper := &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{ID: "imp1"}} - imp1Ext, err := imp1Wrapper.GetImpExt() - assert.NoError(t, err, "Failed to get ImpExt") - imp1Prebid := &openrtb_ext.ExtImpPrebid{Bidder: make(map[string]json.RawMessage)} - for _, bidder := range bidders { - imp1Prebid.Bidder[bidder] = json.RawMessage(`{}`) - } - imp1Ext.SetPrebid(imp1Prebid) - - //---imp2--- - imp2Wrapper := &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{ID: "imp2"}} - imp2Ext, err := imp2Wrapper.GetImpExt() - assert.NoError(t, err, "Failed to get ImpExt") - imp2Prebid := &openrtb_ext.ExtImpPrebid{Bidder: make(map[string]json.RawMessage)} - - for _, bidder := range bidders { - imp2Prebid.Bidder[bidder] = json.RawMessage(`{}`) - } - imp2Ext.SetPrebid(imp2Prebid) - - rw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}} - rw.SetImp([]*openrtb_ext.ImpWrapper{imp1Wrapper, imp2Wrapper}) - - return rw -} - -func mockRequestWrapperWithImpExtPrebidNil(t *testing.T) *openrtb_ext.RequestWrapper { - impWrapper := &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{ID: "imp1"}} - - impExt, err := impWrapper.GetImpExt() - assert.NoError(t, err, "Failed to get ImpExt") - impExt.SetPrebid(nil) - rw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}} - rw.SetImp([]*openrtb_ext.ImpWrapper{impWrapper}) - - return rw -} - -func mockRequestWrapperWithInvalidImpExt(t *testing.T) *openrtb_ext.RequestWrapper { - impWrapper := &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{ID: "imp1", Ext: json.RawMessage(`{"prebid":invalid}`)}} - rw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}} - rw.SetImp([]*openrtb_ext.ImpWrapper{impWrapper}) - - return rw -} - -func mockRequestWrapperWithEmptyImp(t *testing.T) *openrtb_ext.RequestWrapper { - rw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}} - rw.SetImp([]*openrtb_ext.ImpWrapper{}) - return rw -} - -func mockRequestWrapperWithImpExtNil(t *testing.T) *openrtb_ext.RequestWrapper { - impWrapper := &openrtb_ext.ImpWrapper{Imp: &openrtb2.Imp{ID: "imp1"}} - rw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}} - rw.SetImp([]*openrtb_ext.ImpWrapper{impWrapper}) - return rw -} - -// Helper function to compare maps -func compareMaps(a, b map[string]map[string]json.RawMessage) bool { - if len(a) != len(b) { - return false - } - for key, val := range a { - if len(val) != len(b[key]) { - return false - } - for subKey, subVal := range val { - if string(subVal) != string(b[key][subKey]) { - return false - } - } - } - return true -} diff --git a/modules/prebid/rulesengine/tree_builder_test.go b/modules/prebid/rulesengine/tree_builder_test.go index 3dfbcdc09f..38fc6a9ae5 100644 --- a/modules/prebid/rulesengine/tree_builder_test.go +++ b/modules/prebid/rulesengine/tree_builder_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "testing" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/rules" @@ -85,13 +84,13 @@ func TestBuildTree(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - builder := &treeBuilder[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + builder := &treeBuilder[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ Config: tt.modelGroup, SchemaFuncFactory: rules.NewRequestSchemaFunction, ResultFuncFactory: NewProcessedAuctionRequestResultFunction, } - tree := rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + tree := rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, } err := builder.Build(&tree) if tt.expectErr { @@ -109,13 +108,13 @@ func TestBuildTreeFullConfigNoErrors(t *testing.T) { err := jsonutil.Unmarshal(GetFullConf(), &modelGroup) assert.NoError(t, err) - builder := &treeBuilder[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + builder := &treeBuilder[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ Config: modelGroup, SchemaFuncFactory: rules.NewRequestSchemaFunction, ResultFuncFactory: NewProcessedAuctionRequestResultFunction, } - tree := rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{}, + tree := rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{}, } err = builder.Build(&tree) diff --git a/modules/prebid/rulesengine/tree_test.go b/modules/prebid/rulesengine/tree_test.go index 98d4d401e8..4769a2fc49 100644 --- a/modules/prebid/rulesengine/tree_test.go +++ b/modules/prebid/rulesengine/tree_test.go @@ -15,33 +15,38 @@ func TestExecuteRulesFullConfig(t *testing.T) { rw := BuildTestRequestWrapper() rules := BuildTestRules(t) - result := hs.HookResult[hs.ProcessedAuctionRequestPayload]{ + hookResult := hs.HookResult[hs.ProcessedAuctionRequestPayload]{ ChangeSet: hs.ChangeSet[hs.ProcessedAuctionRequestPayload]{}, } + result := ProcessedAuctionHookResult{ + HookResult: hookResult, + AllowedBidders: make(map[string]struct{}), + } + err := rules.Run(rw, &result) assert.NoError(t, err, "unexpected error") - assert.NotEmptyf(t, result.ChangeSet, "change set is empty") - assert.Len(t, result.ChangeSet.Mutations(), 1) - assert.Equal(t, hs.MutationUpdate, result.ChangeSet.Mutations()[0].Type()) + assert.NotEmptyf(t, result.HookResult.ChangeSet, "change set is empty") + assert.Len(t, result.HookResult.ChangeSet.Mutations(), 1) + assert.Equal(t, hs.MutationDelete, result.HookResult.ChangeSet.Mutations()[0].Type()) } -func BuildTestRules(t *testing.T) rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]] { - devCountryFunc, errDevCountry := rules.NewDeviceCountryIn(json.RawMessage(`{"countries": ["USA"]}`)) +func BuildTestRules(t *testing.T) rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult] { + devCountryFunc, errDevCountry := rules.NewDeviceCountryIn(json.RawMessage(`{"countries": ["JPN"]}`)) assert.NoError(t, errDevCountry, "unexpected error in NewDeviceCountryIn") resFuncTrue, errNewIncludeBidders := NewIncludeBidders(json.RawMessage(`{"bidders": ["bidderA"]}`)) assert.NoError(t, errNewIncludeBidders, "unexpected error in NewIncludeBidders") resFuncFalse, errNewExcludeBidders := NewExcludeBidders(json.RawMessage(`{"bidders": ["bidderB"]}`)) assert.NoError(t, errNewExcludeBidders, "unexpected error in NewExcludeBidders") - rules := rules.Tree[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ - Root: &rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + rules := rules.Tree[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ SchemaFunction: devCountryFunc, - Children: map[string]*rules.Node[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{ + Children: map[string]*rules.Node[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{ "true": { - ResultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{resFuncTrue}, + ResultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{resFuncTrue}, }, "false": { - ResultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, hs.HookResult[hs.ProcessedAuctionRequestPayload]]{resFuncFalse}, + ResultFunctions: []rules.ResultFunction[openrtb_ext.RequestWrapper, ProcessedAuctionHookResult]{resFuncFalse}, }, }, }, From 54ca3774bcb670f208c6d938becf6dfb64df03aa Mon Sep 17 00:00:00 2001 From: Sigma Software Date: Tue, 19 Aug 2025 17:40:21 +0000 Subject: [PATCH 056/272] Account: Support bid rounding options (#4470) --- config/account.go | 10 +++ config/config_test.go | 3 + exchange/auction.go | 4 +- exchange/exchange.go | 8 +-- exchange/exchange_test.go | 22 +++---- exchange/price_granularity.go | 28 +++++++-- exchange/price_granularity_test.go | 99 +++++++++++++++++++++++++++++- exchange/targeting_test.go | 2 +- 8 files changed, 153 insertions(+), 23 deletions(-) diff --git a/config/account.go b/config/account.go index c87ce5d1b1..fbd434fcfb 100644 --- a/config/account.go +++ b/config/account.go @@ -23,6 +23,15 @@ const ( ChannelDOOH ChannelType = "dooh" ) +type BidRoundingMode string + +const ( + RoundingModeDown BidRoundingMode = "down" + RoundingModeTrue BidRoundingMode = "true" + RoundingModeTimeSplit BidRoundingMode = "timesplit" + RoundingModeUp BidRoundingMode = "up" +) + // Account represents a publisher account configuration type Account struct { ID string `mapstructure:"id" json:"id"` @@ -41,6 +50,7 @@ type Account struct { Validations Validations `mapstructure:"validations" json:"validations"` DefaultBidLimit int `mapstructure:"default_bid_limit" json:"default_bid_limit"` BidAdjustments *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"` + BidRounding BidRoundingMode `mapstructure:"bid_rounding" json:"bid_rounding,omitempty"` Privacy AccountPrivacy `mapstructure:"privacy" json:"privacy"` PreferredMediaType openrtb_ext.PreferredMediaType `mapstructure:"preferredmediatype" json:"preferredmediatype"` TargetingPrefix string `mapstructure:"targeting_prefix" json:"targeting_prefix"` diff --git a/config/config_test.go b/config/config_test.go index 49248e8ed6..b9cb99ad72 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -549,6 +549,7 @@ account_defaults: period_sec: 2000 max_age_sec: 6000 max_schema_dims: 10 + bid_rounding: up bidadjustments: mediatype: '*': @@ -723,6 +724,8 @@ func TestFullConfig(t *testing.T) { cmpInts(t, "account_defaults.price_floors.fetch.max_age_sec", 6000, cfg.AccountDefaults.PriceFloors.Fetcher.MaxAge) cmpInts(t, "account_defaults.price_floors.fetch.max_schema_dims", 10, cfg.AccountDefaults.PriceFloors.Fetcher.MaxSchemaDims) + assert.Equal(t, RoundingModeUp, cfg.AccountDefaults.BidRounding) + // Assert the DSA was correctly unmarshalled and DefaultUnpacked was built correctly expectedDSA := AccountDSA{ Default: "{\"dsarequired\":3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", diff --git a/exchange/auction.go b/exchange/auction.go index 4d5b8e0037..ff1e28302c 100644 --- a/exchange/auction.go +++ b/exchange/auction.go @@ -185,12 +185,12 @@ func (a *auction) validateAndUpdateMultiBid(adapterBids map[openrtb_ext.BidderNa } } -func (a *auction) setRoundedPrices(targetingData targetData) { +func (a *auction) setRoundedPrices(targetingData targetData, account config.Account) { roundedPrices := make(map[*entities.PbsOrtbBid]string, 5*len(a.winningBids)) for _, topBidsPerImp := range a.allBidsByBidder { for _, topBidsPerBidder := range topBidsPerImp { for _, topBid := range topBidsPerBidder { - roundedPrices[topBid] = GetPriceBucket(*topBid.Bid, targetingData) + roundedPrices[topBid] = GetPriceBucket(*topBid.Bid, targetingData, account) } } } diff --git a/exchange/exchange.go b/exchange/exchange.go index 6a883a73ca..8c5d698275 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -448,7 +448,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog //If includebrandcategory is present in ext then CE feature is on. if requestExtPrebid.Targeting != nil && requestExtPrebid.Targeting.IncludeBrandCategory != nil { var rejections []string - bidCategory, adapterBids, rejections, err = applyCategoryMapping(ctx, *requestExtPrebid.Targeting, adapterBids, e.categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &seatNonBidBuilder) + bidCategory, adapterBids, rejections, err = applyCategoryMapping(ctx, *requestExtPrebid.Targeting, adapterBids, e.categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &seatNonBidBuilder, r.Account) if err != nil { return nil, fmt.Errorf("Error in category mapping : %s", err.Error()) } @@ -480,7 +480,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog // A non-nil auction is only needed if targeting is active. (It is used below this block to extract cache keys) auc = newAuction(adapterBids, len(r.BidRequestWrapper.Imp), targData.preferDeals) auc.validateAndUpdateMultiBid(adapterBids, targData.preferDeals, r.Account.DefaultBidLimit) - auc.setRoundedPrices(*targData) + auc.setRoundedPrices(*targData, r.Account) if requestExtPrebid.SupportDeals { dealErrs := applyDealSupport(r.BidRequestWrapper.BidRequest, auc, bidCategory, multiBidMap) @@ -1028,7 +1028,7 @@ func encodeBidResponseExt(bidResponseExt *openrtb_ext.ExtBidResponse) ([]byte, e return buffer.Bytes(), err } -func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestTargeting, seatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, categoriesFetcher stored_requests.CategoryFetcher, targData *targetData, booleanGenerator deduplicateChanceGenerator, seatNonBidBuilder *SeatNonBidBuilder) (map[string]string, map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, []string, error) { +func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestTargeting, seatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, categoriesFetcher stored_requests.CategoryFetcher, targData *targetData, booleanGenerator deduplicateChanceGenerator, seatNonBidBuilder *SeatNonBidBuilder, account config.Account) (map[string]string, map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, []string, error) { res := make(map[string]string) type bidDedupe struct { @@ -1112,7 +1112,7 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT // TODO: consider should we remove bids with zero duration here? - priceBucket = GetPriceBucket(*bid.Bid, *targData) + priceBucket = GetPriceBucket(*bid.Bid, *targData, account) newDur, err := findDurationRange(duration, targeting.DurationRangeSec) if err != nil { diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index 2e8fcbaa9d..4756f5b4b6 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -2614,7 +2614,7 @@ func TestCategoryMapping(t *testing.T) { adapterBids[bidderName1] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.Equal(t, nil, err, "Category mapping error should be empty") assert.Equal(t, 1, len(rejections), "There should be 1 bid rejection message") @@ -2669,7 +2669,7 @@ func TestCategoryMappingNoIncludeBrandCategory(t *testing.T) { adapterBids[bidderName1] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.Equal(t, nil, err, "Category mapping error should be empty") assert.Empty(t, rejections, "There should be no bid rejection messages") @@ -2721,7 +2721,7 @@ func TestCategoryMappingTranslateCategoriesNil(t *testing.T) { adapterBids[bidderName1] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.Equal(t, nil, err, "Category mapping error should be empty") assert.Equal(t, 1, len(rejections), "There should be 1 bid rejection message") @@ -2803,7 +2803,7 @@ func TestCategoryMappingTranslateCategoriesFalse(t *testing.T) { adapterBids[bidderName1] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.Equal(t, nil, err, "Category mapping error should be empty") assert.Empty(t, rejections, "There should be no bid rejection messages") @@ -2881,7 +2881,7 @@ func TestCategoryDedupe(t *testing.T) { }, } deduplicateGenerator := fakeBooleanGenerator{value: tt.dedupeGeneratorValue} - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &deduplicateGenerator, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &deduplicateGenerator, &SeatNonBidBuilder{}, config.Account{}) assert.Nil(t, err) assert.Equal(t, 3, len(rejections)) @@ -2950,7 +2950,7 @@ func TestNoCategoryDedupe(t *testing.T) { adapterBids[bidderName1] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.Equal(t, nil, err, "Category mapping error should be empty") assert.Equal(t, 2, len(rejections), "There should be 2 bid rejection messages") @@ -3015,7 +3015,7 @@ func TestCategoryMappingBidderName(t *testing.T) { adapterBids[bidderName1] = &seatBid1 adapterBids[bidderName2] = &seatBid2 - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.NoError(t, err, "Category mapping error should be empty") assert.Empty(t, rejections, "There should be 0 bid rejection messages") @@ -3069,7 +3069,7 @@ func TestCategoryMappingBidderNameNoCategories(t *testing.T) { adapterBids[bidderName1] = &seatBid1 adapterBids[bidderName2] = &seatBid2 - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.NoError(t, err, "Category mapping error should be empty") assert.Empty(t, rejections, "There should be 0 bid rejection messages") @@ -3170,7 +3170,7 @@ func TestBidRejectionErrors(t *testing.T) { adapterBids[bidderName] = &seatBid - bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *test.reqExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *test.reqExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) if len(test.expectedCatDur) > 0 { // Bid deduplication case @@ -3233,7 +3233,7 @@ func TestCategoryMappingTwoBiddersOneBidEachNoCategorySamePrice(t *testing.T) { adapterBids[bidderNameApn1] = &seatBidApn1 adapterBids[bidderNameApn2] = &seatBidApn2 - bidCategory, _, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}) + bidCategory, _, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &randomDeduplicateBidBooleanGenerator{}, &SeatNonBidBuilder{}, config.Account{}) assert.NoError(t, err, "Category mapping error should be empty") assert.Len(t, rejections, 1, "There should be 1 bid rejection message") @@ -3317,7 +3317,7 @@ func TestCategoryMappingTwoBiddersManyBidsEachNoCategorySamePrice(t *testing.T) adapterBids[bidderNameApn1] = &seatBidApn1 adapterBids[bidderNameApn2] = &seatBidApn2 - _, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &fakeBooleanGenerator{value: true}, &SeatNonBidBuilder{}) + _, adapterBids, rejections, err := applyCategoryMapping(context.TODO(), *requestExt.Prebid.Targeting, adapterBids, categoriesFetcher, targData, &fakeBooleanGenerator{value: true}, &SeatNonBidBuilder{}, config.Account{}) assert.NoError(t, err, "Category mapping error should be empty") diff --git a/exchange/price_granularity.go b/exchange/price_granularity.go index ba62c1aa4a..b1d5073cd3 100644 --- a/exchange/price_granularity.go +++ b/exchange/price_granularity.go @@ -2,14 +2,16 @@ package exchange import ( "math" + "math/rand" "strconv" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/openrtb_ext" ) // GetPriceBucket is the externally facing function for computing CPM buckets -func GetPriceBucket(bid openrtb2.Bid, targetingData targetData) string { +func GetPriceBucket(bid openrtb2.Bid, targetingData targetData, account config.Account) string { cpmStr := "" bucketMax := 0.0 bucketMin := 0.0 @@ -46,13 +48,31 @@ func GetPriceBucket(bid openrtb2.Bid, targetingData targetData) string { cpmStr = strconv.FormatFloat(bucketMax, 'f', precision, 64) } else if increment > 0 { // If increment exists, get cpm string value - cpmStr = getCpmTarget(cpm, bucketMin, increment, precision) + cpmStr = getCpmTarget(cpm, bucketMin, increment, precision, account.BidRounding) } return cpmStr } -func getCpmTarget(cpm float64, bucketMin float64, increment float64, precision int) string { - roundedCPM := math.Floor((cpm-bucketMin)/increment)*increment + bucketMin +func getCpmTarget(cpm float64, bucketMin float64, increment float64, precision int, rounding config.BidRoundingMode) string { + increments := (cpm - bucketMin) / increment + var incrementsRounded float64 + switch rounding { + case config.RoundingModeTrue: + incrementsRounded = math.Round(increments) + case config.RoundingModeTimeSplit: + if rand.Intn(2) == 1 { + incrementsRounded = math.Floor(increments) + } else { + incrementsRounded = math.Ceil(increments) + } + case config.RoundingModeUp: + incrementsRounded = math.Ceil(increments) + case config.RoundingModeDown: + fallthrough + default: + incrementsRounded = math.Floor(increments) + } + roundedCPM := incrementsRounded*increment + bucketMin return strconv.FormatFloat(roundedCPM, 'f', precision, 64) } diff --git a/exchange/price_granularity_test.go b/exchange/price_granularity_test.go index bb0e5e7d73..277696b88d 100644 --- a/exchange/price_granularity_test.go +++ b/exchange/price_granularity_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/ptrutil" "github.com/stretchr/testify/assert" @@ -194,8 +195,104 @@ func TestGetPriceBucketString(t *testing.T) { for _, testGroup := range testGroups { for i, test := range testGroup.testCases { var priceBucket string - assert.NotPanics(t, func() { priceBucket = GetPriceBucket(testGroup.bid, test.targetData) }, "Group: %s Granularity: %d", testGroup.groupDesc, i) + assert.NotPanics(t, func() { + priceBucket = GetPriceBucket(testGroup.bid, test.targetData, config.Account{BidRounding: config.RoundingModeDown}) + }, "Group: %s Granularity: %d", testGroup.groupDesc, i) assert.Equal(t, test.expectedPriceBucket, priceBucket, "Group: %s Granularity: %s :: Expected %s, got %s from %f", testGroup.groupDesc, test.granularityId, test.expectedPriceBucket, priceBucket, testGroup.bid.Price) } } } + +func TestGetPriceBucketRounding(t *testing.T) { + granularity, _ := openrtb_ext.NewPriceGranularityFromLegacyID("auto") + target := targetData{priceGranularity: granularity} + + // Define test cases + tests := []struct { + desc string + bid openrtb2.Bid + account config.Account + expectedPriceBuckets []string + }{ + { + "Rounding down, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{BidRounding: config.RoundingModeDown}, + []string{"1.85"}, + }, + { + "Rounding down, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{BidRounding: config.RoundingModeDown}, + []string{"1.85"}, + }, + { + "Rounding up, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{BidRounding: config.RoundingModeUp}, + []string{"1.90"}, + }, + { + "Rounding up, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{BidRounding: config.RoundingModeUp}, + []string{"1.90"}, + }, + { + "Rounding true, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{BidRounding: config.RoundingModeTrue}, + []string{"1.85"}, + }, + { + "Rounding true, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{BidRounding: config.RoundingModeTrue}, + []string{"1.90"}, + }, + { + "Rounding timestplit, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{BidRounding: config.RoundingModeTimeSplit}, + []string{"1.85", "1.90"}, + }, + { + "Rounding timestplit, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{BidRounding: config.RoundingModeTimeSplit}, + []string{"1.85", "1.90"}, + }, + { + "Rounding default, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{}, + []string{"1.85"}, + }, + { + "Rounding default, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{}, + []string{"1.85"}, + }, + { + "Rounding invalid, lower half", + openrtb2.Bid{Price: 1.87}, + config.Account{BidRounding: "invalid"}, + []string{"1.85"}, + }, + { + "Rounding invalid, upper half", + openrtb2.Bid{Price: 1.88}, + config.Account{BidRounding: "invalid"}, + []string{"1.85"}, + }, + } + + for _, test := range tests { + var priceBucket string + assert.NotPanics(t, func() { + priceBucket = GetPriceBucket(test.bid, target, test.account) + }, "Case: %s", test.desc) + assert.Contains(t, test.expectedPriceBuckets, priceBucket, "Case: %s Rounding mode: %s :: Expected %s, got %s from %f", test.desc, test.account.BidRounding, test.expectedPriceBuckets, priceBucket, test.bid.Price) + } +} diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index db35656082..d798f22e9b 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -1215,7 +1215,7 @@ func TestSetTargeting(t *testing.T) { for _, test := range TargetingTests { auc := &test.Auction // Set rounded prices from the auction data - auc.setRoundedPrices(test.TargetData) + auc.setRoundedPrices(test.TargetData, config.Account{}) winningBids := make(map[string]*entities.PbsOrtbBid) // Set winning bids from the auction data for imp, bidsByBidder := range auc.allBidsByBidder { From 120a1b53798d2f6eaf54b6346faf91b56b378905 Mon Sep 17 00:00:00 2001 From: Sandy Janicki Date: Tue, 19 Aug 2025 11:51:06 -0600 Subject: [PATCH 057/272] Sovrn: Fix passing through imp.ext.gpid (#4413) --- adapters/sovrn/sovrn.go | 7 - .../sovrntest/supplemental/adunitcode.json | 11 +- .../sovrn/sovrntest/supplemental/fpd.json | 3 +- .../supplemental/invalid-adunitcode.json | 124 ------------------ 4 files changed, 9 insertions(+), 136 deletions(-) delete mode 100644 adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json diff --git a/adapters/sovrn/sovrn.go b/adapters/sovrn/sovrn.go index 91ca9d3ce1..8276c07045 100644 --- a/adapters/sovrn/sovrn.go +++ b/adapters/sovrn/sovrn.go @@ -81,11 +81,6 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt imp.BidFloor = extBidFloor } - var impExtBuffer []byte - impExtBuffer, err = json.Marshal(&sovrnImpExt{ - Bidder: sovrnExt, - AdUnitCode: sovrnExt.AdUnitCode, - }) if err != nil { errs = append(errs, &errortypes.BadInput{ Message: err.Error(), @@ -93,8 +88,6 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt continue } - imp.Ext = impExtBuffer - // Validate video params if appropriate video := imp.Video if video != nil { diff --git a/adapters/sovrn/sovrntest/supplemental/adunitcode.json b/adapters/sovrn/sovrntest/supplemental/adunitcode.json index c913e226bc..f075cbd393 100644 --- a/adapters/sovrn/sovrntest/supplemental/adunitcode.json +++ b/adapters/sovrn/sovrntest/supplemental/adunitcode.json @@ -19,8 +19,10 @@ "ext": { "bidder": { "tagid": "123456", - "adunitcode": "sovrn_auc" - } + "adunitcode": "sovrn_auc_bidder" + }, + "gpid": "test-gpid", + "adunitcode": "sovrn_auc" } } ], @@ -64,8 +66,9 @@ "adunitcode": "sovrn_auc", "bidder": { "tagid": "123456", - "adunitcode": "sovrn_auc" - } + "adunitcode": "sovrn_auc_bidder" + }, + "gpid": "test-gpid" } } ], diff --git a/adapters/sovrn/sovrntest/supplemental/fpd.json b/adapters/sovrn/sovrntest/supplemental/fpd.json index c9b56703f8..4ec5a4f4cb 100644 --- a/adapters/sovrn/sovrntest/supplemental/fpd.json +++ b/adapters/sovrn/sovrntest/supplemental/fpd.json @@ -86,7 +86,8 @@ "tagid": "123456", "ext": { "bidder": { - "tagid": "123456" + "tagid": "123456", + "anotherid": "654321" } } } diff --git a/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json b/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json deleted file mode 100644 index 444bba2152..0000000000 --- a/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "AdUnitCode": "sovrn_auc", - "bidder": { - "tagid": "123456" - } - } - } - ], - "device": { }, - "site": { - "domain": "www.publisher.com", - "page": "http://www.publisher.com/awesome/site" - }, - "user": { - "buyeruid": "test_reader_id" - } - }, - - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": ["application/json"], - "Cookie": ["ljt_reader=test_reader_id"] - }, - "uri": "http://sovrn.com/test/endpoint", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "tagid": "123456", - "ext": { - "bidder": { - "tagid": "123456" - } - } - } - ], - "site": { - "domain": "www.publisher.com", - "page": "http://www.publisher.com/awesome/site" - }, - "user": { - "buyeruid": "test_reader_id" - }, - "device": { } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "a_449642_554a13d3b9f348fba707cf83f0f63800", - "impid": "test-imp-id", - "price": 3.5, - "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800", - "adm": "some-test-ad", - "w": 300, - "h": 250 - } - ] - } - ] - } - } - } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "a_449642_554a13d3b9f348fba707cf83f0f63800", - "impid": "test-imp-id", - "price": 3.5, - "adm": "some-test-ad", - "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800", - "w": 300, - "h": 250 - }, - "type": "banner" - } - ] - } - ] -} From b3b0e2dcf4d1c4d7c266380c31bbfe7778b010ca Mon Sep 17 00:00:00 2001 From: Guillaume Laubier Date: Tue, 19 Aug 2025 20:13:46 +0200 Subject: [PATCH 058/272] Smartadserver: Add second endpoint for programmatic guaranteed (#4467) Co-authored-by: Guillaume Laubier --- adapters/smartadserver/smartadserver.go | 78 +++++++++-- .../multi-banner-programmatic-guaranteed.json | 127 ++++++++++++++++++ .../exemplary/multi-banner.json | 3 +- ...simple-banner-programmatic-guaranteed.json | 98 ++++++++++++++ openrtb_ext/imp_smartadserver.go | 19 ++- 5 files changed, 305 insertions(+), 20 deletions(-) create mode 100644 adapters/smartadserver/smartadservertest/exemplary/multi-banner-programmatic-guaranteed.json create mode 100644 adapters/smartadserver/smartadservertest/exemplary/simple-banner-programmatic-guaranteed.json diff --git a/adapters/smartadserver/smartadserver.go b/adapters/smartadserver/smartadserver.go index 837d46c725..1dc801a90d 100644 --- a/adapters/smartadserver/smartadserver.go +++ b/adapters/smartadserver/smartadserver.go @@ -17,14 +17,21 @@ import ( ) type SmartAdserverAdapter struct { - host string - Server config.Server + defaultHost string + secondaryHost string + Server config.Server +} + +type PendingImpAndExt struct { + imp openrtb2.Imp + ext openrtb_ext.ExtImpSmartadserverOut } // Builder builds a new instance of the SmartAdserver adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { bidder := &SmartAdserverAdapter{ - host: config.Endpoint, + defaultHost: config.Endpoint, + secondaryHost: "https://prebid-global.smartadserver.com", } return bidder, nil } @@ -59,7 +66,10 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf smartRequest.Site.Publisher = &publisher } + var pendingImpsAndExts []PendingImpAndExt var imps []openrtb2.Imp + isProgrammaticGuaranteed := false + impExtKey := "bidder" // Filter out impressions that do not have the proper bidder extensions for _, imp := range request.Imp { @@ -71,18 +81,48 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf continue } - var smartadserverExt openrtb_ext.ExtImpSmartadserver - if err := jsonutil.Unmarshal(bidderExt.Bidder, &smartadserverExt); err != nil { + var smartadserverExtIn openrtb_ext.ExtImpSmartadserverIn + if err := jsonutil.Unmarshal(bidderExt.Bidder, &smartadserverExtIn); err != nil { errs = append(errs, &errortypes.BadInput{ Message: "Error parsing smartadserverExt parameters", }) continue } - imps = append(imps, imp) + if !isProgrammaticGuaranteed && smartadserverExtIn.ProgrammaticGuaranteed { + isProgrammaticGuaranteed = true + impExtKey = "smartadserver" + } + + pendingImpsAndExts = append(pendingImpsAndExts, PendingImpAndExt{imp, openrtb_ext.ExtImpSmartadserverOut(smartadserverExtIn)}) + + // Properly set publisher id from extentions for coming request + smartRequest.Site.Publisher.ID = strconv.Itoa(smartadserverExtIn.NetworkID) + } + + // Loop again to serialize extension properly + for _, pendingImpAndExt := range pendingImpsAndExts { + var completeExt map[string]any + if err := json.Unmarshal(pendingImpAndExt.imp.Ext, &completeExt); err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: "Error parsing imp.Ext object", + }) + continue + } + + // Delete `bidder` extensions, then write it again with either `bidder` or `smartadserver` key, without unwanted elements. + delete(completeExt, "bidder") + completeExt[impExtKey] = pendingImpAndExt.ext + + var errMarshal error + if pendingImpAndExt.imp.Ext, errMarshal = json.Marshal(completeExt); errMarshal != nil { + errs = append(errs, &errortypes.BadInput{ + Message: errMarshal.Error(), + }) + continue + } - // Adding publisher id. - smartRequest.Site.Publisher.ID = strconv.Itoa(smartadserverExt.NetworkID) + imps = append(imps, pendingImpAndExt.imp) } // Only create the request if it has at least one correctly formatted impression @@ -97,7 +137,7 @@ func (a *SmartAdserverAdapter) MakeRequests(request *openrtb2.BidRequest, reqInf return nil, errs } - url, err := a.BuildEndpointURL() + url, err := a.BuildEndpointURL(isProgrammaticGuaranteed) if url == "" { errs = append(errs, err) return nil, errs @@ -158,16 +198,26 @@ func (a *SmartAdserverAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex } // BuildEndpointURL : Builds endpoint url -func (a *SmartAdserverAdapter) BuildEndpointURL() (string, error) { - uri, err := url.Parse(a.host) +func (a *SmartAdserverAdapter) BuildEndpointURL(isProgrammaticGuaranteed bool) (string, error) { + host := a.defaultHost + + if isProgrammaticGuaranteed { + host = a.secondaryHost + } + + uri, err := url.Parse(host) if err != nil || uri.Scheme == "" || uri.Host == "" { return "", &errortypes.BadInput{ - Message: "Malformed URL: " + a.host + ".", + Message: "Malformed URL: " + host + ".", } } - uri.Path = path.Join(uri.Path, "api/bid") - uri.RawQuery = "callerId=5" + if isProgrammaticGuaranteed { + uri.Path = path.Join(uri.Path, "ortb") + } else { + uri.Path = path.Join(uri.Path, "api/bid") + uri.RawQuery = "callerId=5" + } return uri.String(), nil } diff --git a/adapters/smartadserver/smartadservertest/exemplary/multi-banner-programmatic-guaranteed.json b/adapters/smartadserver/smartadservertest/exemplary/multi-banner-programmatic-guaranteed.json new file mode 100644 index 0000000000..4ec852b651 --- /dev/null +++ b/adapters/smartadserver/smartadservertest/exemplary/multi-banner-programmatic-guaranteed.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "test-request-multi-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "siteId": 1, + "pageId": 2, + "formatId": 3, + "networkId": 73, + "programmaticGuaranteed": false + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [{"w": 300, "h": 150}] + }, + "ext": { + "bidder": { + "siteId": 1, + "pageId": 2, + "formatId": 4, + "networkId": 73, + "programmaticGuaranteed": true + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid-global.smartadserver.com/ortb", + "body": { + "id": "test-request-multi-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "smartadserver": { + "siteId": 1, + "pageId": 2, + "formatId": 3, + "networkId": 73 + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [{"w": 300, "h": 150}] + }, + "ext": { + "smartadserver": { + "siteId": 1, + "pageId": 2, + "formatId": 4, + "networkId": 73 + } + } + } + ], + "site": { + "publisher": { + "id": "73" + } + } + }, + "impIDs":["test-imp-id-1","test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-multi-id", + "seatbid": [ + { + "seat": "smartadserver", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801", + "impid": "test-imp-id-2", + "price": 0.800000, + "adm": "some-test-ad", + "crid": "crid_11", + "mtype": 1, + "h": 150, + "w": 300 + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801", + "impid": "test-imp-id-2", + "price": 0.8, + "adm": "some-test-ad", + "crid": "crid_11", + "mtype": 1, + "w": 300, + "h": 150 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json index 50ac6025a9..6f0988a660 100644 --- a/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json +++ b/adapters/smartadserver/smartadservertest/exemplary/multi-banner.json @@ -12,7 +12,8 @@ "siteId": 1, "pageId": 2, "formatId": 3, - "networkId": 73 + "networkId": 73, + "programmaticGuaranteed": false } } }, diff --git a/adapters/smartadserver/smartadservertest/exemplary/simple-banner-programmatic-guaranteed.json b/adapters/smartadserver/smartadservertest/exemplary/simple-banner-programmatic-guaranteed.json new file mode 100644 index 0000000000..91e0c328d1 --- /dev/null +++ b/adapters/smartadserver/smartadservertest/exemplary/simple-banner-programmatic-guaranteed.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "siteId": 1, + "pageId": 2, + "formatId": 3, + "networkId": 73, + "programmaticGuaranteed": true + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid-global.smartadserver.com/ortb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "smartadserver": { + "siteId": 1, + "pageId": 2, + "formatId": 3, + "networkId": 73 + } + } + } + ], + "site": { + "publisher": { + "id": "73" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "smartadserver", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "mtype": 1 + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/openrtb_ext/imp_smartadserver.go b/openrtb_ext/imp_smartadserver.go index 6f6a5df60d..f18eeb4114 100644 --- a/openrtb_ext/imp_smartadserver.go +++ b/openrtb_ext/imp_smartadserver.go @@ -1,9 +1,18 @@ package openrtb_ext // ExtImpSmartadserver defines the contract for bidrequest.imp[i].ext.prebid.bidder.smartadserver -type ExtImpSmartadserver struct { - SiteID int `json:"siteId"` - PageID int `json:"pageId"` - FormatID int `json:"formatId"` - NetworkID int `json:"networkId"` +type ExtImpSmartadserverIn struct { + SiteID int `json:"siteId"` + PageID int `json:"pageId"` + FormatID int `json:"formatId"` + NetworkID int `json:"networkId"` + ProgrammaticGuaranteed bool `json:"programmaticGuaranteed"` +} + +type ExtImpSmartadserverOut struct { + SiteID int `json:"siteId"` + PageID int `json:"pageId"` + FormatID int `json:"formatId"` + NetworkID int `json:"networkId"` + ProgrammaticGuaranteed bool `json:"-"` } From df73a4feae2cf6c5f0de9b6627ef83d30181c7dd Mon Sep 17 00:00:00 2001 From: mabielinski-wpm <155963187+mabielinski-wpm@users.noreply.github.com> Date: Tue, 19 Aug 2025 20:41:31 +0200 Subject: [PATCH 059/272] sspBC: Updates moving operations to backend service (#4351) --- adapters/sspBC/sspbc.go | 385 +++--------------- adapters/sspBC/sspbc_test.go | 58 +++ adapters/sspBC/sspbctest/exemplary/audio.json | 127 ++++++ .../exemplary/banner-fromtemplate.json | 153 ------- ...le-imps.json => banner-multiple-imps.json} | 153 ++++--- ...atted-onecode.json => banner-onecode.json} | 87 ++-- .../{banner-preformatted.json => banner.json} | 93 +++-- .../sspBC/sspbctest/exemplary/native.json | 123 ++++++ adapters/sspBC/sspbctest/exemplary/video.json | 133 ++++++ .../bad_request_without_site.json | 42 -- .../sspbctest/supplemental/bad_response.json | 73 ++-- ...bad_response_with_incorrect_bid_type.json} | 87 ++-- .../bad_response_with_incorrect_impid.json | 136 ------- .../request_with_diffrent_siteid.json | 154 ------- ...request_with_incorrect_imp_bidder_ext.json | 149 ------- .../request_with_incorrect_imp_ext.json | 147 ------- ...request_with_standard_and_onecode_imp.json | 130 +++--- .../supplemental/request_with_test.json | 156 ------- .../request_without_banner_format.json | 90 ++-- .../supplemental/request_without_ext_id.json | 151 ------- .../request_without_ext_site_id.json | 152 ------- .../sspbctest/supplemental/status_204.json | 74 ++-- .../sspbctest/supplemental/status_400.json | 76 ++-- static/bidder-info/sspBC.yaml | 5 +- 24 files changed, 977 insertions(+), 1957 deletions(-) create mode 100644 adapters/sspBC/sspbctest/exemplary/audio.json delete mode 100644 adapters/sspBC/sspbctest/exemplary/banner-fromtemplate.json rename adapters/sspBC/sspbctest/exemplary/{banner-preformatted-multiple-imps.json => banner-multiple-imps.json} (59%) rename adapters/sspBC/sspbctest/exemplary/{banner-preformatted-onecode.json => banner-onecode.json} (61%) rename adapters/sspBC/sspbctest/exemplary/{banner-preformatted.json => banner.json} (60%) create mode 100644 adapters/sspBC/sspbctest/exemplary/native.json create mode 100644 adapters/sspBC/sspbctest/exemplary/video.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/bad_request_without_site.json rename adapters/sspBC/sspbctest/supplemental/{bad_response_without_adm.json => bad_response_with_incorrect_bid_type.json} (56%) delete mode 100644 adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_impid.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_with_diffrent_siteid.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_bidder_ext.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_ext.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_with_test.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_without_ext_id.json delete mode 100644 adapters/sspBC/sspbctest/supplemental/request_without_ext_site_id.json diff --git a/adapters/sspBC/sspbc.go b/adapters/sspBC/sspbc.go index ae7d5f40e1..4a12ddaa51 100644 --- a/adapters/sspBC/sspbc.go +++ b/adapters/sspBC/sspbc.go @@ -1,135 +1,70 @@ package sspBC import ( - "bytes" "encoding/json" - "errors" "fmt" - "html/template" "net/http" "net/url" - "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/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" ) const ( - adapterVersion = "5.8" - impFallbackSize = "1x1" - requestTypeStandard = 1 - requestTypeOneCode = 2 - requestTypeTest = 3 - prebidServerIntegrationType = "4" + adapterVersion = "6.0" ) -var ( - errSiteNill = errors.New("site cannot be nill") - errImpNotFound = errors.New("imp not found") - errNotSupportedFormat = errors.New("bid format is not supported") +type ( + adapter struct { + endpoint string + } + requestInfo struct { + PbsEntryPoint metrics.RequestType + } + requestData struct { + Request *openrtb2.BidRequest `json:"bidRequest"` + RequestInfo *requestInfo `json:"requestInfo"` + } ) -// mcAd defines the MC payload for banner ads. -type mcAd struct { - Id string `json:"id"` - Seat string `json:"seat"` - SeatBid []openrtb2.SeatBid `json:"seatbid"` -} - -// adSlotData defines struct used for the oneCode detection. -type adSlotData struct { - PbSlot string `json:"pbslot"` - PbSize string `json:"pbsize"` -} - -// templatePayload represents the banner template payload. -type templatePayload struct { - SiteId string `json:"siteid"` - SlotId string `json:"slotid"` - AdLabel string `json:"adlabel"` - PubId string `json:"pubid"` - Page string `json:"page"` - Referer string `json:"referer"` - McAd mcAd `json:"mcad"` - Inver string `json:"inver"` -} - -// requestImpExt represents the ext field of the request imp field. -type requestImpExt struct { - Data adSlotData `json:"data"` -} - -// responseExt represents ext data added by proxy. -type responseExt struct { - AdLabel string `json:"adlabel"` - PublisherId string `json:"pubid"` - SiteId string `json:"siteid"` - SlotId string `json:"slotid"` -} - -type adapter struct { - endpoint string - bannerTemplate *template.Template -} - // ---------------ADAPTER INTERFACE------------------ // Builder builds a new instance of the sspBC adapter -func Builder(_ openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - // HTML template used to create banner ads - const bannerHTML = `
` - - bannerTemplate, err := template.New("banner").Parse(bannerHTML) +func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) { + endpoint, err := buildAdapterEndpoint(config.Endpoint, adapterVersion) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to build sspbc adapter endpoint: %w", err) } bidder := &adapter{ - endpoint: config.Endpoint, - bannerTemplate: bannerTemplate, + endpoint: endpoint, } return bidder, nil } -func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - formattedRequest, err := formatSspBcRequest(request) - if err != nil { - return nil, []error{err} - } - - requestJSON, err := json.Marshal(formattedRequest) - if err != nil { - return nil, []error{err} +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, extraRequestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + sspBcRequest := &requestData{ + Request: request, + RequestInfo: &requestInfo{ + PbsEntryPoint: extraRequestInfo.PbsEntryPoint, + }, } - requestURL, err := url.Parse(a.endpoint) + requestJSON, err := json.Marshal(sspBcRequest) if err != nil { return nil, []error{err} } - // add query parameters to request - queryParams := requestURL.Query() - queryParams.Add("bdver", adapterVersion) - queryParams.Add("inver", prebidServerIntegrationType) - requestURL.RawQuery = queryParams.Encode() - requestData := &adapters.RequestData{ Method: http.MethodPost, - Uri: requestURL.String(), + Uri: a.endpoint, Body: requestJSON, - ImpIDs: getImpIDs(formattedRequest.Imp), + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), } return []*adapters.RequestData{requestData}, nil @@ -142,7 +77,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest if externalResponse.StatusCode != http.StatusOK { err := &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Unexpected status code: %d.", externalResponse.StatusCode), + Message: fmt.Sprintf("unexpected status code: %d.", externalResponse.StatusCode), } return nil, []error{err} } @@ -157,253 +92,49 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest var errors []error for _, seatBid := range response.SeatBid { - for _, bid := range seatBid.Bid { - if err := a.impToBid(internalRequest, seatBid, bid, bidResponse); err != nil { - errors = append(errors, err) + for i := range seatBid.Bid { + bid := seatBid.Bid[i] + bidType, err := getBidType(bid) + if err != nil { + return nil, []error{err} } - } - } - - return bidResponse, errors -} - -func (a *adapter) impToBid(internalRequest *openrtb2.BidRequest, seatBid openrtb2.SeatBid, bid openrtb2.Bid, - bidResponse *adapters.BidderResponse) error { - var bidType openrtb_ext.BidType - - /* - Determine bid type - At this moment we only check if bid contains Adm property - - Later updates will check for video & native data - */ - if bid.AdM != "" { - bidType = openrtb_ext.BidTypeBanner - } - - /* - Recover original ImpID - (stored on request in TagID) - */ - impID, err := getOriginalImpID(bid.ImpID, internalRequest.Imp) - if err != nil { - return err - } - bid.ImpID = impID - - // read additional data from proxy - var bidDataExt responseExt - if err := jsonutil.Unmarshal(bid.Ext, &bidDataExt); err != nil { - return err - } - /* - use correct ad creation method for a detected bid type - right now, we are only creating banner ads - if type is not detected / supported, throw error - */ - if bidType != openrtb_ext.BidTypeBanner { - return errNotSupportedFormat - } - - var adCreationError error - bid.AdM, adCreationError = a.createBannerAd(bid, bidDataExt, internalRequest, seatBid.Seat) - if adCreationError != nil { - return adCreationError - } - // append bid to responses - bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ - Bid: &bid, - BidType: bidType, - }) - - return nil -} - -func getOriginalImpID(impID string, imps []openrtb2.Imp) (string, error) { - for _, imp := range imps { - if imp.ID == impID { - return imp.TagID, nil - } - } - - return "", errImpNotFound -} - -func (a *adapter) createBannerAd(bid openrtb2.Bid, ext responseExt, request *openrtb2.BidRequest, seat string) (string, error) { - if strings.Contains(bid.AdM, "") { - // Banner ad is already formatted - return bid.AdM, nil - } - - // create McAd payload - var mcad = mcAd{ - Id: request.ID, - Seat: seat, - SeatBid: []openrtb2.SeatBid{ - {Bid: []openrtb2.Bid{bid}}, - }, - } - - bannerData := &templatePayload{ - SiteId: ext.SiteId, - SlotId: ext.SlotId, - AdLabel: ext.AdLabel, - PubId: ext.PublisherId, - Page: request.Site.Page, - Referer: request.Site.Ref, - McAd: mcad, - Inver: prebidServerIntegrationType, - } - - var filledTemplate bytes.Buffer - if err := a.bannerTemplate.Execute(&filledTemplate, bannerData); err != nil { - return "", err - } - - return filledTemplate.String(), nil -} - -func getImpSize(imp openrtb2.Imp) string { - if imp.Banner == nil || len(imp.Banner.Format) == 0 { - return impFallbackSize - } - - var ( - areaMax int64 - impSize = impFallbackSize - ) - for _, size := range imp.Banner.Format { - area := size.W * size.H - if area > areaMax { - areaMax = area - impSize = fmt.Sprintf("%dx%d", size.W, size.H) + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) } } - return impSize -} - -// getBidParameters reads additional data for this imp (site id , placement id, test) -// Errors in parameters do not break imp flow, and thus are not returned -func getBidParameters(imp openrtb2.Imp) openrtb_ext.ExtImpSspbc { - var extBidder adapters.ExtImpBidder - var extSSP openrtb_ext.ExtImpSspbc - - if err := jsonutil.Unmarshal(imp.Ext, &extBidder); err == nil { - _ = jsonutil.Unmarshal(extBidder.Bidder, &extSSP) - } - - return extSSP + return bidResponse, errors } -// getRequestType checks what kind of request we have. It can either be: -// - a standard request, where all Imps have complete site / placement data -// - a oneCodeRequest, where site / placement data has to be determined by server -// - a test request, where server returns fixed example ads -func getRequestType(request *openrtb2.BidRequest) int { - incompleteImps := 0 - - for _, imp := range request.Imp { - // Read data for this imp - extSSP := getBidParameters(imp) - - if extSSP.IsTest != 0 { - return requestTypeTest - } - - if extSSP.SiteId == "" || extSSP.Id == "" { - incompleteImps += 1 +func getBidType(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.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported MType: %d.", bid.MType), } } - - if incompleteImps > 0 { - return requestTypeOneCode - } - - return requestTypeStandard } -func formatSspBcRequest(request *openrtb2.BidRequest) (*openrtb2.BidRequest, error) { - if request.Site == nil { - return nil, errSiteNill - } - - var siteID string - - // determine what kind of request we are dealing with - requestType := getRequestType(request) - - for i, imp := range request.Imp { - // read ext data for the impression - extSSP := getBidParameters(imp) - - // store SiteID - if extSSP.SiteId != "" { - siteID = extSSP.SiteId - } - - // save current imp.id (adUnit name) as imp.tagid - // we will recover it in makeBids - imp.TagID = imp.ID - - // if there is a placement id, and this is not a oneCodeRequest, use it in imp.id - if extSSP.Id != "" && requestType != requestTypeOneCode { - imp.ID = extSSP.Id - } - - // check imp size and update e.ext - send pbslot, pbsize - // inability to set bid.ext will cause request to be invalid - impSize := getImpSize(imp) - impExt := requestImpExt{ - Data: adSlotData{ - PbSlot: imp.TagID, - PbSize: impSize, - }, - } - - impExtJSON, err := json.Marshal(impExt) - if err != nil { - return nil, err - } - imp.Ext = impExtJSON - // save updated imp - request.Imp[i] = imp - } - - siteCopy := *request.Site - request.Site = &siteCopy - - /* - update site ID - for oneCode request it has to be blank - for other requests it should be equal to - SiteId from one of the bids - */ - if requestType == requestTypeOneCode || siteID == "" { - request.Site.ID = "" - } else { - request.Site.ID = siteID - } - - // add domain info - if siteURL, err := url.Parse(request.Site.Page); err == nil { - request.Site.Domain = siteURL.Hostname() - } - - // set TEST Flag - if requestType == requestTypeTest { - request.Test = 1 +func buildAdapterEndpoint(endpoint string, adapterVersion string) (string, error) { + endpointURL, err := url.Parse(endpoint) + if err != nil { + return "", fmt.Errorf("unable to parse endpoint URL: %w", err) } - return request, nil -} + params := endpointURL.Query() + params.Add("bdver", adapterVersion) + endpointURL.RawQuery = params.Encode() -// getImpIDs uses imp.TagID instead of imp.ID as formattedRequest stores imp.ID in imp.TagID -func getImpIDs(imps []openrtb2.Imp) []string { - impIDs := make([]string, len(imps)) - for i := range imps { - impIDs[i] = imps[i].TagID - } - return impIDs + return endpointURL.String(), nil } diff --git a/adapters/sspBC/sspbc_test.go b/adapters/sspBC/sspbc_test.go index 2d709f4c46..f2fdc7dae6 100644 --- a/adapters/sspBC/sspbc_test.go +++ b/adapters/sspBC/sspbc_test.go @@ -1,10 +1,14 @@ package sspBC import ( + "encoding/json" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -18,3 +22,57 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "sspbctest", bidder) } + +func TestInvalidEndpointURL(t *testing.T) { + invalidEndpointURL := "http://ssp.wp.test /bidder/" + + _, buildErr := Builder(openrtb_ext.BidderSspBC, config.Adapter{ + Endpoint: invalidEndpointURL}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr == nil { + t.Fatalf("Adapter allowed invalid endpoint URL %v", invalidEndpointURL) + } +} + +func TestMakeRequests(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderSspBC, config.Adapter{ + Endpoint: "http://ssp.wp.test/bidder/"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + w, h := int64(300), int64(250) + + imp1 := openrtb2.Imp{ + ID: "imp1", + Ext: json.RawMessage("{\"bidder\":{\"siteId\": \"237503\", \"id\": \"005\"}}"), + Banner: &openrtb2.Banner{ + W: &w, + H: &h, + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }} + + inputRequest := openrtb2.BidRequest{ + User: &openrtb2.User{ID: "Test123"}, + Imp: []openrtb2.Imp{imp1}, + Site: &openrtb2.Site{ + Publisher: &openrtb2.Publisher{ + ID: "12345", + }, + }, + ID: "1234", + } + + inputExtraRequestInfo := adapters.ExtraRequestInfo{ + PbsEntryPoint: metrics.ReqTypeORTB2Web, + } + + _, err := bidder.MakeRequests(&inputRequest, &inputExtraRequestInfo) + + if err != nil { + t.Fatalf("Make requests function returned unexpected error %v", err) + } +} diff --git a/adapters/sspBC/sspbctest/exemplary/audio.json b/adapters/sspBC/sspbctest/exemplary/audio.json new file mode 100644 index 0000000000..60b7f86821 --- /dev/null +++ b/adapters/sspBC/sspbctest/exemplary/audio.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + }, + "secure": 1, + "audio": { + "mimes": ["audio/mp3"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2] + }, + "tagid": "ad-test1" + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "regs": { + "ext": { + "gdpr": 1 + } + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", + "body": { + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "audio": { + "mimes": ["audio/mp3"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + }, + "regs": { + "ext": { + "gdpr": 1 + } + } + }, + "requestInfo": { + "PbsEntryPoint": "" + } + }, + "impIDs":["slot"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "id": "test-request", + "seatbid": [ + { + "seat": "sspbc-test", + "bid": [{ + "adm": "test-audio-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 3 + }] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "adm": "test-audio-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/exemplary/banner-fromtemplate.json b/adapters/sspBC/sspbctest/exemplary/banner-fromtemplate.json deleted file mode 100644 index a8af949612..0000000000 --- a/adapters/sspBC/sspbctest/exemplary/banner-fromtemplate.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503", - "id": "005" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "some-test-ad", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "005", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"some-test-ad\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/exemplary/banner-preformatted-multiple-imps.json b/adapters/sspBC/sspbctest/exemplary/banner-multiple-imps.json similarity index 59% rename from adapters/sspBC/sspbctest/exemplary/banner-preformatted-multiple-imps.json rename to adapters/sspBC/sspbctest/exemplary/banner-multiple-imps.json index 15856d4ae4..94821abdda 100644 --- a/adapters/sspBC/sspbctest/exemplary/banner-preformatted-multiple-imps.json +++ b/adapters/sspBC/sspbctest/exemplary/banner-multiple-imps.json @@ -18,7 +18,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" }, { "id": "slot2", @@ -36,7 +37,8 @@ "h": 600 } ] - } + }, + "tagid": "ad-test2" } ], "site": { @@ -59,65 +61,69 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } }, - "tagid": "slot1", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot1", - "pbsize": "300x250" + { + "id": "slot2", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "ad-test2", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "037" + } } } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" }, - { - "id": "037", - "banner": { - "format": [ - { - "w": 300, - "h": 600 - } - ] + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot2", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot2", - "pbsize": "300x600" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot1","slot2"] @@ -132,22 +138,26 @@ "bid": [ { "adm": "<!--preformatted-->test_ad_1", + "nurl": "www.test.com", "adomain": [ "sspbc-test" ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot1" + "tagid": "ad-test1" }, "w": 300, "h": 250, "id": "response-005", - "impid": "005", - "price": 20 + "impid": "slot1", + "price": 20, + "mtype": 1 } ], "seat": "sspbc-test" @@ -156,28 +166,31 @@ "bid": [ { "adm": "<!--preformatted-->test_ad_2", + "nurl": "www.test.com", "adomain": [ "sspbc-test" ], "crid": "5678", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "037", - "tagid": "slot2" + "tagid": "ad-test2" }, "w": 300, "h": 600, "id": "response-037", - "impid": "037", - "price": 10 + "impid": "slot2", + "price": 10, + "mtype": 1 } ], "seat": "sspbc-test" } - ], - "sn": "sspbc-test" + ] } } } @@ -192,6 +205,7 @@ "impid": "slot1", "price": 20, "adm": "<!--preformatted-->test_ad_1", + "nurl": "www.test.com", "adomain": [ "sspbc-test" ], @@ -199,12 +213,15 @@ "w": 300, "h": 250, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot1" - } + "tagid": "ad-test1" + }, + "mtype": 1 }, "type": "banner" }, @@ -214,6 +231,7 @@ "impid": "slot2", "price": 10, "adm": "<!--preformatted-->test_ad_2", + "nurl": "www.test.com", "adomain": [ "sspbc-test" ], @@ -221,12 +239,15 @@ "w": 300, "h": 600, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "037", - "tagid": "slot2" - } + "tagid": "ad-test2" + }, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/sspBC/sspbctest/exemplary/banner-preformatted-onecode.json b/adapters/sspBC/sspbctest/exemplary/banner-onecode.json similarity index 61% rename from adapters/sspBC/sspbctest/exemplary/banner-preformatted-onecode.json rename to adapters/sspBC/sspbctest/exemplary/banner-onecode.json index c700d9e584..c7ded494c6 100644 --- a/adapters/sspBC/sspbctest/exemplary/banner-preformatted-onecode.json +++ b/adapters/sspBC/sspbctest/exemplary/banner-onecode.json @@ -13,7 +13,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { @@ -36,45 +37,45 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": {} + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] @@ -94,17 +95,20 @@ ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" + "tagid": "ad-test1" }, "w": 300, "h": 250, "id": "response-005", "impid": "slot", - "price": 20 + "price": 20, + "mtype": 1 } ], "seat": "sspbc-test" @@ -132,12 +136,15 @@ "w": 300, "h": 250, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" - } + "tagid": "ad-test1" + }, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/sspBC/sspbctest/exemplary/banner-preformatted.json b/adapters/sspBC/sspbctest/exemplary/banner.json similarity index 60% rename from adapters/sspBC/sspbctest/exemplary/banner-preformatted.json rename to adapters/sspBC/sspbctest/exemplary/banner.json index 1a9b22e780..b93d75108e 100644 --- a/adapters/sspBC/sspbctest/exemplary/banner-preformatted.json +++ b/adapters/sspBC/sspbctest/exemplary/banner.json @@ -18,7 +18,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { @@ -41,46 +42,50 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] @@ -100,17 +105,20 @@ ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" + "tagid": "ad-test1" }, "w": 300, "h": 250, "id": "response-005", - "impid": "005", - "price": 20 + "impid": "slot", + "price": 20, + "mtype": 1 } ], "seat": "sspbc-test" @@ -138,12 +146,15 @@ "w": 300, "h": 250, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" - } + "tagid": "ad-test1" + }, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/sspBC/sspbctest/exemplary/native.json b/adapters/sspBC/sspbctest/exemplary/native.json new file mode 100644 index 0000000000..09b0d165d4 --- /dev/null +++ b/adapters/sspBC/sspbctest/exemplary/native.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + }, + "secure": 1, + "native": { + "request": "{json string}", + "ver": "1.2" + }, + "tagid": "ad-test1" + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "regs": { + "ext": { + "gdpr": 1 + } + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", + "body": { + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "native": { + "request": "{json string}", + "ver": "1.2" + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + }, + "regs": { + "ext": { + "gdpr": 1 + } + } + }, + "requestInfo": { + "PbsEntryPoint": "" + } + }, + "impIDs":["slot"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "id": "test-request", + "seatbid": [ + { + "seat": "sspbc-test", + "bid": [{ + "adm": "test-native-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 4 + }] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "adm": "test-native-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/exemplary/video.json b/adapters/sspBC/sspbctest/exemplary/video.json new file mode 100644 index 0000000000..9a941a4421 --- /dev/null +++ b/adapters/sspBC/sspbctest/exemplary/video.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + }, + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 320, + "h": 480 + }, + "tagid": "ad-test1" + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "regs": { + "ext": { + "gdpr": 1 + } + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", + "body": { + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 320, + "h": 480 + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + }, + "regs": { + "ext": { + "gdpr": 1 + } + } + }, + "requestInfo": { + "PbsEntryPoint": "" + } + }, + "impIDs":["slot"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "id": "test-request", + "seatbid": [ + { + "seat": "sspbc-test", + "bid": [ + { + "adm": "test-video-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 2, + "w": 320, + "h": 480 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "adm": "test-video-ad", + "id": "response-005", + "impid": "slot", + "price": 20, + "mtype": 2, + "w": 320, + "h": 480 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/bad_request_without_site.json b/adapters/sspBC/sspbctest/supplemental/bad_request_without_site.json deleted file mode 100644 index c8acc0c82f..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/bad_request_without_site.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503", - "id": "005" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "expectedMakeRequestsErrors": [ - { - "value": "site cannot be nill", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/bad_response.json b/adapters/sspBC/sspbctest/supplemental/bad_response.json index 14f7d4ddb1..73f4239c93 100644 --- a/adapters/sspBC/sspbctest/supplemental/bad_response.json +++ b/adapters/sspBC/sspbctest/supplemental/bad_response.json @@ -18,7 +18,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { @@ -41,46 +42,50 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] diff --git a/adapters/sspBC/sspbctest/supplemental/bad_response_without_adm.json b/adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_bid_type.json similarity index 56% rename from adapters/sspBC/sspbctest/supplemental/bad_response_without_adm.json rename to adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_bid_type.json index f975b66d2c..9b27921099 100644 --- a/adapters/sspBC/sspbctest/supplemental/bad_response_without_adm.json +++ b/adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_bid_type.json @@ -18,7 +18,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { @@ -41,46 +42,50 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] @@ -100,17 +105,20 @@ ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" + "tagid": "ad-test1" }, "w": 300, "h": 250, "id": "response-005", - "impid": "005", - "price": 20 + "impid": "slot", + "price": 20, + "mtype": 0 } ], "seat": "sspbc-test" @@ -121,10 +129,9 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], "expectedMakeBidsErrors": [ { - "value": "bid format is not supported", + "value": "unsupported MType: 0.", "comparison": "literal" } ] diff --git a/adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_impid.json b/adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_impid.json deleted file mode 100644 index 26c9e42cf6..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/bad_response_with_incorrect_impid.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503", - "id": "005" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "incorrect-imp-id", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [] - } - ], - "expectedMakeBidsErrors": [ - { - "value": "imp not found", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_with_diffrent_siteid.json b/adapters/sspBC/sspbctest/supplemental/request_with_diffrent_siteid.json deleted file mode 100644 index 92a77fa840..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_with_diffrent_siteid.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503", - "id": "005" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "id": "diffrent", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "005", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_bidder_ext.json b/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_bidder_ext.json deleted file mode 100644 index 8e089cfefd..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_bidder_ext.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": "incorrect" - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "slot", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_ext.json b/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_ext.json deleted file mode 100644 index 3ab3f998ba..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_with_incorrect_imp_ext.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": "incorrect", - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "slot", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_with_standard_and_onecode_imp.json b/adapters/sspBC/sspbctest/supplemental/request_with_standard_and_onecode_imp.json index 7c864f8c9a..4784ce5968 100644 --- a/adapters/sspBC/sspbctest/supplemental/request_with_standard_and_onecode_imp.json +++ b/adapters/sspBC/sspbctest/supplemental/request_with_standard_and_onecode_imp.json @@ -18,7 +18,8 @@ "h": 250 } ] - } + }, + "tagid": "ad-slot-standard" }, { "id": "slot-onecode", @@ -31,7 +32,8 @@ "h": 600 } ] - } + }, + "tagid": "ad-slot-onecode" } ], "site": { @@ -54,64 +56,64 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "slot-standard", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot-standard", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-slot-standard", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] - }, - "tagid": "slot-standard", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot-standard", - "pbsize": "300x250" } + }, + { + "id": "slot-onecode", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "ad-slot-onecode", + "secure": 1, + "ext": {} } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" }, - { - "id": "slot-onecode", - "banner": { - "format": [ - { - "w": 300, - "h": 600 - } - ] + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot-onecode", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot-onecode", - "pbsize": "300x600" - } + "gdpr": 1 } } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot-standard","slot-onecode"] @@ -131,7 +133,9 @@ ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", @@ -141,7 +145,8 @@ "h": 250, "id": "response-005", "impid": "slot-standard", - "price": 20 + "price": 20, + "mtype": 1 } ], "seat": "sspbc-test" @@ -155,7 +160,9 @@ ], "crid": "5678", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "037", @@ -165,7 +172,8 @@ "h": 600, "id": "response-037", "impid": "slot-onecode", - "price": 10 + "price": 10, + "mtype": 1 } ], "seat": "sspbc-test" @@ -193,12 +201,15 @@ "w": 300, "h": 250, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", "tagid": "slot-standard" - } + }, + "mtype": 1 }, "type": "banner" }, @@ -215,12 +226,15 @@ "w": 300, "h": 600, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "037", "tagid": "slot-onecode" - } + }, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/sspBC/sspbctest/supplemental/request_with_test.json b/adapters/sspBC/sspbctest/supplemental/request_with_test.json deleted file mode 100644 index 70f740b4b6..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_with_test.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503", - "id": "005", - "test": 1 - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "test": 1, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "005", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_without_banner_format.json b/adapters/sspBC/sspbctest/supplemental/request_without_banner_format.json index 7572f88cac..96c1eaab70 100644 --- a/adapters/sspBC/sspbctest/supplemental/request_without_banner_format.json +++ b/adapters/sspBC/sspbctest/supplemental/request_without_banner_format.json @@ -13,7 +13,8 @@ "secure": 1, "banner": { "format": [] - } + }, + "tagid": "ad-test1" } ], "site": { @@ -37,40 +38,45 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": {}, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "1x1" + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": {}, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" + } } } - } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" + ], + "site": { + "id": "237503", + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 + "user": { + "ext": { + "consent": "test_consent" + }, + "buyeruid": "test_user" + }, + "regs": { + "ext": { + "gdpr": 1 + } } - } + }, + "requestInfo": { + "PbsEntryPoint": "" + } }, "impIDs":["slot"] }, @@ -83,23 +89,26 @@ { "bid": [ { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", + "adm": "<!--preformatted-->test_ad", "adomain": [ "sspbc-test" ], "crid": "1234", "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" + "tagid": "ad-test1" }, "w": 300, "h": 250, "id": "response-005", - "impid": "005", - "price": 20 + "impid": "slot", + "price": 20, + "mtype": 1 } ], "seat": "sspbc-test" @@ -119,7 +128,7 @@ "id": "response-005", "impid": "slot", "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", + "adm": "<!--preformatted-->test_ad", "adomain": [ "sspbc-test" ], @@ -127,12 +136,15 @@ "w": 300, "h": 250, "ext": { - "adlabel": "Reklama", + "external": "1", + "platform": "prebidserver", + "pricepl": 0.123, "pubid": "431", "siteid": "237503", "slotid": "005", - "tagid": "slot" - } + "tagid": "ad-test1" + }, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/sspBC/sspbctest/supplemental/request_without_ext_id.json b/adapters/sspBC/sspbctest/supplemental/request_without_ext_id.json deleted file mode 100644 index f7692a91b0..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_without_ext_id.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "237503" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "slot", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/request_without_ext_site_id.json b/adapters/sspBC/sspbctest/supplemental/request_without_ext_site_id.json deleted file mode 100644 index eb04d2f7c7..0000000000 --- a/adapters/sspBC/sspbctest/supplemental/request_without_ext_site_id.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "ext": { - "bidder": { - "siteId": "", - "id": "005" - } - }, - "secure": 1, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", - "body": { - "id": "test-request", - "imp": [ - { - "id": "slot", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "tagid": "slot", - "secure": 1, - "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } - } - } - ], - "site": { - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" - }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } - } - }, - "impIDs":["slot"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "id": "test-request", - "seatbid": [ - { - "bid": [ - { - "adm": "{\"bunch\":\"237503\",\"capping\":\"\",\"server\":\"s\",\"campaign\":\"c\",\"score\":\"1\",\"creations\":[{\"type\":\"image\",\"src\":\"https:\/\/bdr.wpcdn.pl\/tests\/test-300x250.png\",\"trackers\":{},\"width\":300,\"height\":250}],\"code\":\"1\",\"aabVendors\":false,\"slot\":\"005\",\"redir\":\"https:\/\/www.wp.pl\",\"wpclid\":\"1\"}", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - }, - "w": 300, - "h": 250, - "id": "response-005", - "impid": "slot", - "price": 20 - } - ], - "seat": "sspbc-test" - } - ], - "sn": "sspbc-test" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "response-005", - "impid": "slot", - "price": 20, - "adm": "<html><head><title><\/title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style> body { background-color: transparent; margin: 0; padding: 0; }<\/style><script> window.rekid = \"237503\"; window.slot = \"005\"; window.adlabel = 'Reklama'; window.pubid = '431'; window.wp_sn = 'sspbc_go'; window.page = 'https:\\\/\\\/test.page\\\/'; window.ref = 'https:\\\/\\\/test.referer\\\/'; window.mcad = {\"id\":\"test-request\",\"seat\":\"sspbc-test\",\"seatbid\":[{\"bid\":[{\"id\":\"response-005\",\"impid\":\"slot\",\"price\":20,\"adm\":\"{\\\"bunch\\\":\\\"237503\\\",\\\"capping\\\":\\\"\\\",\\\"server\\\":\\\"s\\\",\\\"campaign\\\":\\\"c\\\",\\\"score\\\":\\\"1\\\",\\\"creations\\\":[{\\\"type\\\":\\\"image\\\",\\\"src\\\":\\\"https://bdr.wpcdn.pl/tests/test-300x250.png\\\",\\\"trackers\\\":{},\\\"width\\\":300,\\\"height\\\":250}],\\\"code\\\":\\\"1\\\",\\\"aabVendors\\\":false,\\\"slot\\\":\\\"005\\\",\\\"redir\\\":\\\"https://www.wp.pl\\\",\\\"wpclid\\\":\\\"1\\\"}\",\"adomain\":[\"sspbc-test\"],\"crid\":\"1234\",\"w\":300,\"h\":250,\"ext\":{\"adlabel\":\"Reklama\",\"pubid\":\"431\",\"siteid\":\"237503\",\"slotid\":\"005\",\"tagid\":\"slot\"}}]}]}; window.inver = '4'; <\/script><\/head><body><div id=\"c\"><\/div><script async crossorigin nomodule src=\"\/\/std.wpcdn.pl\/wpjslib\/wpjslib-inline.js\" id=\"wpjslib\"><\/script><script async crossorigin type=\"module\" src=\"\/\/std.wpcdn.pl\/wpjslib6\/wpjslib-inline.js\" id=\"wpjslib6\"><\/script><\/body><\/html>", - "adomain": [ - "sspbc-test" - ], - "crid": "1234", - "w": 300, - "h": 250, - "ext": { - "adlabel": "Reklama", - "pubid": "431", - "siteid": "237503", - "slotid": "005", - "tagid": "slot" - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/sspBC/sspbctest/supplemental/status_204.json b/adapters/sspBC/sspbctest/supplemental/status_204.json index f26421a635..6e4b3c52ae 100644 --- a/adapters/sspBC/sspbctest/supplemental/status_204.json +++ b/adapters/sspBC/sspbctest/supplemental/status_204.json @@ -18,11 +18,11 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { - "id": "237503", "domain": "test.page", "page": "https://test.page/", "ref": "https://test.referer/" @@ -42,46 +42,50 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] diff --git a/adapters/sspBC/sspbctest/supplemental/status_400.json b/adapters/sspBC/sspbctest/supplemental/status_400.json index adf79df5d2..ee6d0b3663 100644 --- a/adapters/sspBC/sspbctest/supplemental/status_400.json +++ b/adapters/sspBC/sspbctest/supplemental/status_400.json @@ -18,11 +18,11 @@ "h": 250 } ] - } + }, + "tagid": "ad-test1" } ], "site": { - "id": "237503", "domain": "test.page", "page": "https://test.page/", "ref": "https://test.referer/" @@ -42,46 +42,50 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://ssp.wp.test/bidder/?bdver=5.8&inver=4", + "uri": "http://ssp.wp.test/bidder/?bdver=6.0", "body": { - "id": "test-request", - "imp": [ - { - "id": "005", - "banner": { - "format": [ - { - "w": 300, - "h": 250 + "bidRequest": { + "id": "test-request", + "imp": [ + { + "id": "slot", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "ad-test1", + "secure": 1, + "ext": { + "bidder": { + "siteId": "237503", + "id": "005" } - ] + } + } + ], + "site": { + "domain": "test.page", + "page": "https://test.page/", + "ref": "https://test.referer/" + }, + "user": { + "ext": { + "consent": "test_consent" }, - "tagid": "slot", - "secure": 1, + "buyeruid": "test_user" + }, + "regs": { "ext": { - "data": { - "pbslot": "slot", - "pbsize": "300x250" - } + "gdpr": 1 } } - ], - "site": { - "id": "237503", - "domain": "test.page", - "page": "https://test.page/", - "ref": "https://test.referer/" }, - "user": { - "ext": { - "consent": "test_consent" - }, - "buyeruid": "test_user" - }, - "regs": { - "ext": { - "gdpr": 1 - } + "requestInfo": { + "PbsEntryPoint": "" } }, "impIDs":["slot"] @@ -94,7 +98,7 @@ ], "expectedMakeBidsErrors": [ { - "value": "Unexpected status code: 400.", + "value": "unexpected status code: 400.", "comparison": "literal" } ] diff --git a/static/bidder-info/sspBC.yaml b/static/bidder-info/sspBC.yaml index 97da8b497c..d1855ec9fe 100644 --- a/static/bidder-info/sspBC.yaml +++ b/static/bidder-info/sspBC.yaml @@ -1,4 +1,4 @@ -endpoint: "https://ssp.wp.pl/v1/bidder/prebidserver" +endpoint: "https://ssp.wp.pl/v2/bidder/prebidserver" maintainer: email: "prebid-dev@grupawp.pl" gvlVendorID: 676 @@ -11,3 +11,6 @@ userSync: iframe: url: https://ssp.wp.pl/bidder/usersync?tcf=2&redirect={{.RedirectURL}} userMacro: $UID + redirect: + url: https://ssp.wp.pl/v1/sync/prebid-server/pixel?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirect={{.RedirectURL}} + userMacro: $UID From 09883a827939103b2be7e6b328d7153e040bb3d3 Mon Sep 17 00:00:00 2001 From: Andrii Rudyk <96918101+And-Rud@users.noreply.github.com> Date: Tue, 19 Aug 2025 21:54:03 +0300 Subject: [PATCH 060/272] New Adapter: Adipolo - Xeworks alias (#4350) Co-authored-by: And-Rud <andrii@xe.works> Co-authored-by: rbstdev <devgit204@xe.works> --- static/bidder-info/adipolo.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 static/bidder-info/adipolo.yaml diff --git a/static/bidder-info/adipolo.yaml b/static/bidder-info/adipolo.yaml new file mode 100644 index 0000000000..0cf1ac3430 --- /dev/null +++ b/static/bidder-info/adipolo.yaml @@ -0,0 +1,11 @@ +aliasOf: xeworks +endpoint: "http://rtb.adipolo.live?pid={{.SourceId}}&host={{.Host}}&pbs=1" +maintainer: + email: "smart@adipolo.com" +userSync: + iframe: + url: "https://sync.adipolo.live/static/adisync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&cb={{.RedirectURL}}" + userMacro: $UID + redirect: + url: "https://sync.adipolo.live/psync?t=s&e=0&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&cb={{.RedirectURL}}" + userMacro: "$UID" \ No newline at end of file From 7ee10502f0559b335632f0a318c597ade9f858f3 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Wed, 20 Aug 2025 00:36:37 +0530 Subject: [PATCH 061/272] Modules: Exitpoint Stage (#4435) --- endpoints/openrtb2/amp_auction.go | 5 +- endpoints/openrtb2/amp_auction_test.go | 5 + endpoints/openrtb2/auction.go | 5 +- endpoints/openrtb2/auction_test.go | 5 + .../sample-requests/hooks/amp_exitpoint.json | 50 ++ .../hooks/auction_exitpoint.json | 47 ++ endpoints/openrtb2/test_utils.go | 22 + hooks/empty_plan.go | 4 + hooks/empty_plan_test.go | 1 + hooks/hookexecution/executor.go | 38 +- hooks/hookexecution/executor_test.go | 473 ++++++++++++++++++ hooks/hookexecution/mocks_test.go | 53 ++ hooks/hookstage/exitpoint.go | 32 ++ hooks/plan.go | 14 +- hooks/plan_test.go | 116 +++++ hooks/repo.go | 13 + modules/helpers.go | 6 + 17 files changed, 885 insertions(+), 4 deletions(-) create mode 100644 endpoints/openrtb2/sample-requests/hooks/amp_exitpoint.json create mode 100644 endpoints/openrtb2/sample-requests/hooks/auction_exitpoint.json create mode 100644 hooks/hookstage/exitpoint.go diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 9bf4c6ab61..631041eee3 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -412,10 +412,13 @@ func sendAmpResponse( // nevertheless we will keep it as such for compatibility reasons. w.Header().Set("Content-Type", "text/plain; charset=utf-8") + // Exitpoint will modify the response and set response headers according to hook implementation. + finalResponse := hookExecutor.ExecuteExitpointStage(ampResponse, w) + // If an error happens when encoding the response, there isn't much we can do. // If we've sent _any_ bytes, then Go would have sent the 200 status code first. // That status code can't be un-sent... so the best we can do is log the error. - if err := enc.Encode(ampResponse); err != nil { + if err := enc.Encode(finalResponse); err != nil { labels.RequestStatus = metrics.RequestStatusNetworkErr ao.Errors = append(ao.Errors, fmt.Errorf("/openrtb2/amp Failed to send response: %v", err)) } diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go index 44f2e36f7d..126d86802b 100644 --- a/endpoints/openrtb2/amp_auction_test.go +++ b/endpoints/openrtb2/amp_auction_test.go @@ -2199,6 +2199,11 @@ func TestValidAmpResponseWhenRequestRejected(t *testing.T) { }, }, }, + { + description: "assert response returned by exitpoint stage", + file: "sample-requests/hooks/amp_exitpoint.json", + planBuilder: mockPlanBuilder{exitpointPlan: makePlan[hookstage.Exitpoint](mockUpdateResponseHook{})}, + }, } for _, tc := range testCases { diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index d18981a87c..14f2fdee55 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -382,10 +382,13 @@ func sendAuctionResponse( w.Header().Set("Content-Type", "application/json") + // Exitpoint will modify the response and set response headers according to hook implementation. + finalResponse := hookExecutor.ExecuteExitpointStage(response, w) + // If an error happens when encoding the response, there isn't much we can do. // If we've sent _any_ bytes, then Go would have sent the 200 status code first. // That status code can't be un-sent... so the best we can do is log the error. - if err := enc.Encode(response); err != nil { + if err := enc.Encode(finalResponse); err != nil { labels.RequestStatus = metrics.RequestStatusNetworkErr ao.Errors = append(ao.Errors, fmt.Errorf("/openrtb2/auction Failed to send response: %v", err)) } diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index 1573de1fcb..09f2d013c3 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -4915,6 +4915,11 @@ func TestValidResponseAfterExecutingStages(t *testing.T) { file: "sample-requests/hooks/auction.json", planBuilder: hooksPlanBuilder, }, + { + description: "Assert modified bidresponse after exitpoint hook implementation", + file: "sample-requests/hooks/auction_exitpoint.json", + planBuilder: mockPlanBuilder{exitpointPlan: makePlan[hookstage.Exitpoint](mockUpdateResponseHook{})}, + }, } for _, tc := range testCases { diff --git a/endpoints/openrtb2/sample-requests/hooks/amp_exitpoint.json b/endpoints/openrtb2/sample-requests/hooks/amp_exitpoint.json new file mode 100644 index 0000000000..18e46916ea --- /dev/null +++ b/endpoints/openrtb2/sample-requests/hooks/amp_exitpoint.json @@ -0,0 +1,50 @@ +{ + "description": "Amp Exitpoint", + "query": "tag_id=101&trace=verbose", + "config": { + "mockBidders": [ + { + "bidderName": "pubmatic", + "currency": "USD", + "price": 2 + } + ] + }, + "mockBidRequest": { + "id": "my-req-id", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "prebid": { + "bidder": { + "pubmatic": { + "publisherId": 12345 + } + } + } + } + } + ], + "ext": { + "prebid": { + "debug": true + } + } + }, + "expectedAmpResponse": { + "id": "modified-id" + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/endpoints/openrtb2/sample-requests/hooks/auction_exitpoint.json b/endpoints/openrtb2/sample-requests/hooks/auction_exitpoint.json new file mode 100644 index 0000000000..d3c74646df --- /dev/null +++ b/endpoints/openrtb2/sample-requests/hooks/auction_exitpoint.json @@ -0,0 +1,47 @@ +{ + "description": "Auction Exitpoint", + "config": { + "mockBidders": [ + { + "bidderName": "pubmatic", + "currency": "USD", + "price": 1.00 + } + ] + }, + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "pubmatic": { + "publisherId": 12345 + } + } + } + ], + "tmax": 500, + "test": 1, + "ext": { + "prebid": { + "trace": "verbose" + } + } + }, + "expectedBidResponse": { + "id": "modified-id" + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go index b19cb5bada..67195d356d 100644 --- a/endpoints/openrtb2/test_utils.go +++ b/endpoints/openrtb2/test_utils.go @@ -1529,6 +1529,7 @@ type mockPlanBuilder struct { rawBidderResponsePlan hooks.Plan[hookstage.RawBidderResponse] allProcessedBidResponsesPlan hooks.Plan[hookstage.AllProcessedBidResponses] auctionResponsePlan hooks.Plan[hookstage.AuctionResponse] + exitpointPlan hooks.Plan[hookstage.Exitpoint] } func (m mockPlanBuilder) PlanForEntrypointStage(_ string) hooks.Plan[hookstage.Entrypoint] { @@ -1559,6 +1560,10 @@ func (m mockPlanBuilder) PlanForAuctionResponseStage(_ string, _ *config.Account return m.auctionResponsePlan } +func (m mockPlanBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return m.exitpointPlan +} + func makePlan[H any](hook H) hooks.Plan[H] { return hooks.Plan[H]{ { @@ -1742,3 +1747,20 @@ func (m mockUpdateHook) HandleRawAuctionHook( ) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) { return hookstage.HookResult[hookstage.RawAuctionRequestPayload]{}, nil } + +type mockUpdateResponseHook struct{} + +func (e mockUpdateResponseHook) HandleExitpointHook( + _ context.Context, + _ hookstage.ModuleInvocationContext, + _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} + c.AddMutation( + func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + payload.Response = &openrtb2.BidResponse{ID: "modified-id"} + payload.W.Header().Set("Content-Type", "application/json") + return payload, nil + }, hookstage.MutationUpdate, "exitpoint", "bidResponse.json-response") + + return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil +} diff --git a/hooks/empty_plan.go b/hooks/empty_plan.go index 72c1a9276d..ea86a31405 100644 --- a/hooks/empty_plan.go +++ b/hooks/empty_plan.go @@ -36,3 +36,7 @@ func (e EmptyPlanBuilder) PlanForAllProcessedBidResponsesStage(endpoint string, func (e EmptyPlanBuilder) PlanForAuctionResponseStage(endpoint string, account *config.Account) Plan[hookstage.AuctionResponse] { return nil } + +func (e EmptyPlanBuilder) PlanForExitpointStage(endpoint string, account *config.Account) Plan[hookstage.Exitpoint] { + return nil +} diff --git a/hooks/empty_plan_test.go b/hooks/empty_plan_test.go index 4a512a9d0d..5c0f07015b 100644 --- a/hooks/empty_plan_test.go +++ b/hooks/empty_plan_test.go @@ -18,4 +18,5 @@ func TestEmptyPlanBuilder(t *testing.T) { assert.Len(t, planBuilder.PlanForRawBidderResponseStage(endpoint, nil), 0, message, StageRawBidderResponse) assert.Len(t, planBuilder.PlanForAllProcessedBidResponsesStage(endpoint, nil), 0, message, StageAllProcessedBidResponses) assert.Len(t, planBuilder.PlanForAuctionResponseStage(endpoint, nil), 0, message, StageAuctionResponse) + assert.Len(t, planBuilder.PlanForExitpointStage(endpoint, nil), 0, message, StageExitpoint) } diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go index a1ff81f971..d448bda806 100644 --- a/hooks/hookexecution/executor.go +++ b/hooks/hookexecution/executor.go @@ -29,6 +29,7 @@ const ( entityAuctionRequest entity = "auction-request" entityAuctionResponse entity = "auction_response" entityAllProcessedBidResponses entity = "all_processed_bid_responses" + entityExitpoint entity = "exitpoint" ) type StageExecutor interface { @@ -39,6 +40,7 @@ type StageExecutor interface { ExecuteRawBidderResponseStage(response *adapters.BidderResponse, bidder string) *RejectError ExecuteAllProcessedBidResponsesStage(adapterBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid) ExecuteAuctionResponseStage(response *openrtb2.BidResponse) + ExecuteExitpointStage(response any, w http.ResponseWriter) any } type HookStageExecutor interface { @@ -295,6 +297,35 @@ func (e *hookExecutor) ExecuteAuctionResponseStage(response *openrtb2.BidRespons e.pushStageOutcome(outcome) } +func (e *hookExecutor) ExecuteExitpointStage(response any, w http.ResponseWriter) any { + plan := e.planBuilder.PlanForExitpointStage(e.endpoint, e.account) + if len(plan) == 0 { + return response + } + + handler := func( + ctx context.Context, + moduleCtx hookstage.ModuleInvocationContext, + hook hookstage.Exitpoint, + payload hookstage.ExitpointPaylaod, + ) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + return hook.HandleExitpointHook(ctx, moduleCtx, payload) + } + + stageName := hooks.StageExitpoint.String() + executionCtx := e.newContext(stageName) + payload := hookstage.ExitpointPaylaod{W: w, Response: response} + + outcome, payload, context, _ := executeStage(executionCtx, plan, payload, handler, e.metricEngine) + outcome.Entity = entityExitpoint + outcome.Stage = stageName + + e.saveModuleContexts(context) + e.pushStageOutcome(outcome) + + return payload.Response +} + func (e *hookExecutor) newContext(stage string) executionContext { return executionContext{ account: e.account, @@ -353,4 +384,9 @@ func (executor EmptyHookExecutor) ExecuteRawBidderResponseStage(_ *adapters.Bidd func (executor EmptyHookExecutor) ExecuteAllProcessedBidResponsesStage(_ map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid) { } -func (executor EmptyHookExecutor) ExecuteAuctionResponseStage(_ *openrtb2.BidResponse) {} +func (executor EmptyHookExecutor) ExecuteAuctionResponseStage(_ *openrtb2.BidResponse) { +} + +func (executor EmptyHookExecutor) ExecuteExitpointStage(response any, _ http.ResponseWriter) any { + return response +} diff --git a/hooks/hookexecution/executor_test.go b/hooks/hookexecution/executor_test.go index 5e19f24a96..4ce9933c83 100644 --- a/hooks/hookexecution/executor_test.go +++ b/hooks/hookexecution/executor_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "net/http" + "net/http/httptest" "net/url" "testing" "time" @@ -1952,6 +1953,386 @@ func TestExecuteAuctionResponseStage(t *testing.T) { } } +func TestExecuteExitpointStage(t *testing.T) { + type fields struct { + account *config.Account + endpoint string + planBuilder hooks.ExecutionPlanBuilder + metricEngine metrics.MetricsEngine + activityControl privacy.ActivityControl + } + type args struct { + response any + w http.ResponseWriter + } + tests := []struct { + name string + fields fields + args args + expectedResponse any + expectedResponseHeaders http.Header + expectedModuleContexts *moduleContexts + expectedStageOutcomes []StageOutcome + }{ + { + name: "payload not changed when plan is empty", + fields: fields{ + account: &config.Account{ + ID: "test-account", + }, + endpoint: EndpointAuction, + planBuilder: hooks.EmptyPlanBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ + ID: "test-id", + }, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: &openrtb2.BidResponse{ + ID: "test-id", + }, + expectedResponseHeaders: http.Header{ + "Content-Type": []string{"application/json"}, + }, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedStageOutcomes: []StageOutcome{}, + }, + { + name: "payload changed after hook returned mutation", + fields: fields{ + account: &config.Account{ + ID: "test-account", + }, + endpoint: EndpointAuction, + planBuilder: TestApplyHookMutationsBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ + ID: "test-id", + }, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: `<VAST version="2.0"/>`, + expectedResponseHeaders: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedStageOutcomes: []StageOutcome{ + { + Entity: "exitpoint", + Stage: "exitpoint", + Groups: []GroupOutcome{ + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "foo"}, + Status: StatusSuccess, + Action: ActionUpdate, + DebugMessages: []string{"Hook mutation successfully applied, affected key: exitpoint.bidResponse.custom-response, mutation type: update"}, + }, + }, + }, + }, + }, + }, + }, + { + name: "Stage execution can't be rejected - stage doesn't support rejection", + fields: fields{ + account: &config.Account{ + ID: "test-account", + }, + endpoint: EndpointAuction, + planBuilder: TestRejectPlanBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ID: "test-id"}, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: `<VAST version="2.0"/>`, + expectedResponseHeaders: http.Header{"Content-Type": []string{"application/xml"}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedStageOutcomes: []StageOutcome{ + { + Entity: entityExitpoint, + Stage: hooks.StageExitpoint.String(), + Groups: []GroupOutcome{ + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "baz"}, + Status: StatusExecutionFailure, + Action: "", + Message: "", + DebugMessages: nil, + Errors: []string{"unexpected error"}, + Warnings: nil, + }, + }, + }, + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "foo"}, + Status: StatusExecutionFailure, + Action: "", + Message: "", + DebugMessages: nil, + Errors: []string{ + fmt.Sprintf("Module (name: foobar, hook code: foo) tried to reject request on the %s stage that does not support rejection", hooks.StageExitpoint), + }, + Warnings: nil, + }, + }, + }, + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "bar"}, + Status: StatusSuccess, + Action: ActionUpdate, + Message: "", + DebugMessages: []string{ + fmt.Sprintf("Hook mutation successfully applied, affected key: exitpoint.bidResponse.custom-response, mutation type: %s", hookstage.MutationUpdate), + }, + Errors: nil, + Warnings: nil, + }, + }, + }, + }, + }, + }, + }, + { + name: "Request can be changed when a hook times out", + fields: fields{ + account: &config.Account{ + ID: "test-account", + }, + endpoint: EndpointAuction, + planBuilder: TestWithTimeoutPlanBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ID: "test-id"}, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: `<VAST version="2.0"/>`, + expectedResponseHeaders: http.Header{"Content-Type": []string{"application/xml"}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedStageOutcomes: []StageOutcome{ + { + Entity: entityExitpoint, + Stage: hooks.StageExitpoint.String(), + Groups: []GroupOutcome{ + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "foo"}, + Status: StatusTimeout, + Action: "", + Message: "", + DebugMessages: nil, + Errors: []string{"Hook execution timeout"}, + Warnings: nil, + }, + }, + }, + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "foobar", HookImplCode: "bar"}, + Status: StatusSuccess, + Action: ActionUpdate, + Message: "", + DebugMessages: []string{ + fmt.Sprintf("Hook mutation successfully applied, affected key: exitpoint.bidResponse.custom-response, mutation type: %s", hookstage.MutationUpdate), + }, + Errors: nil, + Warnings: nil, + }, + }, + }, + }, + }, + }, + }, + { + name: "Modules contexts are preserved and correct", + fields: fields{ + account: &config.Account{ID: "test-account"}, + endpoint: EndpointAuction, + planBuilder: TestWithModuleContextsPlanBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ID: "test-id"}, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: &openrtb2.BidResponse{ID: "test-id"}, + expectedResponseHeaders: http.Header{"Content-Type": []string{"application/json"}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ + "module-1": {"exitpoint-ctx-1": "some-ctx-1", "exitpoint-ctx-3": "some-ctx-3"}, + "module-2": {"exitpoint-ctx-2": "some-ctx-2"}, + }}, + expectedStageOutcomes: []StageOutcome{ + { + Entity: entityExitpoint, + Stage: hooks.StageExitpoint.String(), + Groups: []GroupOutcome{ + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "module-1", HookImplCode: "foo"}, + Status: StatusSuccess, + Action: ActionNone, + Message: "", + DebugMessages: nil, + Errors: nil, + Warnings: nil, + }, + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "module-2", HookImplCode: "baz"}, + Status: StatusSuccess, + Action: ActionNone, + Message: "", + DebugMessages: nil, + Errors: nil, + Warnings: nil, + }, + }, + }, + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "module-1", HookImplCode: "bar"}, + Status: StatusSuccess, + Action: ActionNone, + Message: "", + DebugMessages: nil, + Errors: nil, + Warnings: nil, + }, + }, + }, + }, + }, + }, + }, + { + name: "multiple hooks modify payload", + fields: fields{ + account: &config.Account{ + ID: "test-account", + }, + endpoint: EndpointAuction, + planBuilder: TestMultipleHooksUpdatePayloadBuilder{}, + metricEngine: &metricsConfig.NilMetricsEngine{}, + }, + args: args{ + response: &openrtb2.BidResponse{ + ID: "test-id", + }, + w: func() http.ResponseWriter { + w := httptest.NewRecorder() + w.Header().Set("Content-Type", "application/json") + return w + }(), + }, + expectedResponse: &openrtb2.BidResponse{ID: "modified-id"}, + expectedResponseHeaders: http.Header{ + "Content-Type": []string{"application/json"}, + }, + expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ + "module-1": nil, + "module-2": nil, + }}, + expectedStageOutcomes: []StageOutcome{ + { + Entity: "exitpoint", + Stage: "exitpoint", + Groups: []GroupOutcome{ + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "module-1", HookImplCode: "xml-response"}, + Status: StatusSuccess, + Action: ActionUpdate, + DebugMessages: []string{"Hook mutation successfully applied, affected key: exitpoint.bidResponse.custom-response, mutation type: update"}, + }, + }, + }, + { + InvocationResults: []HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{}, + HookID: HookID{ModuleCode: "module-2", HookImplCode: "json-response"}, + Status: StatusSuccess, + Action: ActionUpdate, + DebugMessages: []string{"Hook mutation successfully applied, affected key: exitpoint.bidResponse.json-response, mutation type: update"}, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NewHookExecutor(tt.fields.planBuilder, tt.fields.endpoint, tt.fields.metricEngine) + e.SetAccount(tt.fields.account) + e.SetActivityControl(tt.fields.activityControl) + newResponse := e.ExecuteExitpointStage(tt.args.response, tt.args.w) + assert.Equal(t, tt.expectedResponse, newResponse, "response is malformed") + assert.Equal(t, tt.expectedResponseHeaders, tt.args.w.Header(), "incorrect response headers") + assert.Equal(t, tt.expectedModuleContexts, e.moduleContexts, "Incorrect module contexts") + + stageOutcomes := e.GetOutcomes() + if len(tt.expectedStageOutcomes) == 0 { + assert.Empty(t, stageOutcomes, "Incorrect stage outcomes.") + } else { + assertEqualStageOutcomes(t, tt.expectedStageOutcomes[0], stageOutcomes[0]) + } + }) + } +} + func TestInterStageContextCommunication(t *testing.T) { body := []byte(`{"foo": "bar"}`) reader := bytes.NewReader(body) @@ -2169,6 +2550,17 @@ func (e TestApplyHookMutationsBuilder) PlanForAuctionResponseStage(_ string, _ * } } +func (e TestApplyHookMutationsBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return hooks.Plan[hookstage.Exitpoint]{ + hooks.Group[hookstage.Exitpoint]{ + Timeout: 2 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: mockUpdateResponseHook{}}, + }, + }, + } +} + type TestRejectPlanBuilder struct { hooks.EmptyPlanBuilder } @@ -2333,6 +2725,31 @@ func (e TestRejectPlanBuilder) PlanForAuctionResponseStage(_ string, _ *config.A } } +func (e TestRejectPlanBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return hooks.Plan[hookstage.Exitpoint]{ + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "baz", Hook: mockErrorHook{}}, + }, + }, + // rejection ignored, stage doesn't support rejection + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: mockRejectHook{}}, + }, + }, + // hook executed and payload updated because this stage doesn't support rejection + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "bar", Hook: mockUpdateResponseHook{}}, + }, + }, + } +} + type TestWithTimeoutPlanBuilder struct { hooks.EmptyPlanBuilder } @@ -2457,6 +2874,23 @@ func (e TestWithTimeoutPlanBuilder) PlanForAuctionResponseStage(_ string, _ *con } } +func (e TestWithTimeoutPlanBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return hooks.Plan[hookstage.Exitpoint]{ + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: mockTimeoutHook{}}, + }, + }, + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "bar", Hook: mockUpdateResponseHook{}}, + }, + }, + } +} + type TestWithModuleContextsPlanBuilder struct { hooks.EmptyPlanBuilder } @@ -2585,6 +3019,24 @@ func (e TestWithModuleContextsPlanBuilder) PlanForAuctionResponseStage(_ string, } } +func (e TestWithModuleContextsPlanBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return hooks.Plan[hookstage.Exitpoint]{ + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "module-1", Code: "foo", Hook: mockModuleContextHook{key: "exitpoint-ctx-1", val: "some-ctx-1"}}, + {Module: "module-2", Code: "baz", Hook: mockModuleContextHook{key: "exitpoint-ctx-2", val: "some-ctx-2"}}, + }, + }, + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "module-1", Code: "bar", Hook: mockModuleContextHook{key: "exitpoint-ctx-3", val: "some-ctx-3"}}, + }, + }, + } +} + type TestAllHookResultsBuilder struct { hooks.EmptyPlanBuilder } @@ -2612,3 +3064,24 @@ func (e TestAllHookResultsBuilder) PlanForEntrypointStage(_ string) hooks.Plan[h }, } } + +type TestMultipleHooksUpdatePayloadBuilder struct { + hooks.EmptyPlanBuilder +} + +func (e TestMultipleHooksUpdatePayloadBuilder) PlanForExitpointStage(_ string, _ *config.Account) hooks.Plan[hookstage.Exitpoint] { + return hooks.Plan[hookstage.Exitpoint]{ + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "module-1", Code: "xml-response", Hook: mockUpdateResponseHook{}}, + }, + }, + hooks.Group[hookstage.Exitpoint]{ + Timeout: 1 * time.Millisecond, + Hooks: []hooks.HookWrapper[hookstage.Exitpoint]{ + {Module: "module-2", Code: "json-response", Hook: mockUpdateResponseAgainHook{}}, + }, + }, + } +} diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go index 1a415adba8..202bd7a63f 100644 --- a/hooks/hookexecution/mocks_test.go +++ b/hooks/hookexecution/mocks_test.go @@ -5,6 +5,7 @@ import ( "errors" "time" + "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/ptrutil" @@ -100,6 +101,10 @@ func (e mockRejectHook) HandleAuctionResponseHook(_ context.Context, _ hookstage return hookstage.HookResult[hookstage.AuctionResponsePayload]{Reject: true}, nil } +func (e mockRejectHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + return hookstage.HookResult[hookstage.ExitpointPaylaod]{Reject: true}, nil +} + type mockTimeoutHook struct{} func (e mockTimeoutHook) HandleEntrypointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { @@ -180,6 +185,17 @@ func (e mockTimeoutHook) HandleAuctionResponseHook(_ context.Context, _ hookstag return hookstage.HookResult[hookstage.AuctionResponsePayload]{ChangeSet: c}, nil } +func (e mockTimeoutHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + time.Sleep(2 * time.Millisecond) + c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} + c.AddMutation(func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + payload.Response = &openrtb2.BidResponse{ID: "another-id"} + return payload, nil + }, hookstage.MutationUpdate, "exitpoint", "bidResponse.id") + + return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil +} + type mockModuleContextHook struct { key, val string } @@ -219,6 +235,11 @@ func (e mockModuleContextHook) HandleAuctionResponseHook(_ context.Context, miCt return hookstage.HookResult[hookstage.AuctionResponsePayload]{ModuleContext: miCtx.ModuleContext}, nil } +func (e mockModuleContextHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + return hookstage.HookResult[hookstage.ExitpointPaylaod]{ModuleContext: miCtx.ModuleContext}, nil +} + type mockFailureHook struct{} func (h mockFailureHook) HandleEntrypointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { @@ -259,6 +280,10 @@ func (h mockErrorHook) HandleAuctionResponseHook(_ context.Context, miCtx hookst return hookstage.HookResult[hookstage.AuctionResponsePayload]{}, errors.New("unexpected error") } +func (h mockErrorHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + return hookstage.HookResult[hookstage.ExitpointPaylaod]{}, errors.New("unexpected error") +} + type mockFailedMutationHook struct{} func (h mockFailedMutationHook) HandleEntrypointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { @@ -385,3 +410,31 @@ func (e mockUpdateBidResponseHook) HandleAuctionResponseHook(_ context.Context, return hookstage.HookResult[hookstage.AuctionResponsePayload]{ChangeSet: c}, nil } + +type mockUpdateResponseHook struct{} + +func (e mockUpdateResponseHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} + c.AddMutation( + func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + payload.Response = `<VAST version="2.0"/>` + payload.W.Header().Set("Content-Type", "application/xml") + return payload, nil + }, hookstage.MutationUpdate, "exitpoint", "bidResponse.custom-response") + + return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil +} + +type mockUpdateResponseAgainHook struct{} + +func (e mockUpdateResponseAgainHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} + c.AddMutation( + func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + payload.Response = &openrtb2.BidResponse{ID: "modified-id"} + payload.W.Header().Set("Content-Type", "application/json") + return payload, nil + }, hookstage.MutationUpdate, "exitpoint", "bidResponse.json-response") + + return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil +} diff --git a/hooks/hookstage/exitpoint.go b/hooks/hookstage/exitpoint.go new file mode 100644 index 0000000000..5746f2eae0 --- /dev/null +++ b/hooks/hookstage/exitpoint.go @@ -0,0 +1,32 @@ +package hookstage + +import ( + "context" + "net/http" +) + +// Exitpoint hooks are invoked just before the response is returned. +// These hooks can fully modify the response based on the module’s implementation. +// They are only triggered if there are no 4XX or 5XX errors during request processing. +// +// At this stage, the account configuration is available, +// allowing hooks to be controlled through the account-level execution plan. +// The account-level module configuration is also passed to the hooks. +// +// Any rejection at this stage is ignored and has no effect. +type Exitpoint interface { + HandleExitpointHook( + context.Context, + ModuleInvocationContext, + ExitpointPaylaod, + ) (HookResult[ExitpointPaylaod], error) +} + +// ExitpointPayload contains a response of any type and a ResponseWriter. +// The response is typically of type *openrtb2.BidResponse and can be modified +// based on the module’s implementation. +// Modules can also add custom headers depending on their response type. +type ExitpointPaylaod struct { + Response any + W http.ResponseWriter +} diff --git a/hooks/plan.go b/hooks/plan.go index 62655f6cf5..25dcd8c4b4 100644 --- a/hooks/plan.go +++ b/hooks/plan.go @@ -19,6 +19,7 @@ const ( StageRawBidderResponse Stage = "raw_bidder_response" StageAllProcessedBidResponses Stage = "all_processed_bid_responses" StageAuctionResponse Stage = "auction_response" + StageExitpoint Stage = "exitpoint" ) func (s Stage) String() string { @@ -27,7 +28,7 @@ func (s Stage) String() string { func (s Stage) IsRejectable() bool { return s != StageAllProcessedBidResponses && - s != StageAuctionResponse + s != StageAuctionResponse && s != StageExitpoint } // ExecutionPlanBuilder is the interface that provides methods @@ -41,6 +42,7 @@ type ExecutionPlanBuilder interface { PlanForRawBidderResponseStage(endpoint string, account *config.Account) Plan[hookstage.RawBidderResponse] PlanForAllProcessedBidResponsesStage(endpoint string, account *config.Account) Plan[hookstage.AllProcessedBidResponses] PlanForAuctionResponseStage(endpoint string, account *config.Account) Plan[hookstage.AuctionResponse] + PlanForExitpointStage(endpoint string, account *config.Account) Plan[hookstage.Exitpoint] } // Plan represents a slice of groups of hooks of a specific type grouped in the established order. @@ -156,6 +158,16 @@ func (p PlanBuilder) PlanForAuctionResponseStage(endpoint string, account *confi ) } +func (p PlanBuilder) PlanForExitpointStage(endpoint string, account *config.Account) Plan[hookstage.Exitpoint] { + return getMergedPlan( + p.hooks, + account, + endpoint, + StageExitpoint, + p.repo.GetExitpointHook, + ) +} + type hookFn[T any] func(moduleName string) (T, bool) func getMergedPlan[T any]( diff --git a/hooks/plan_test.go b/hooks/plan_test.go index fd2d0554e5..5cb44938f7 100644 --- a/hooks/plan_test.go +++ b/hooks/plan_test.go @@ -770,6 +770,112 @@ func TestPlanForAuctionResponseStage(t *testing.T) { } } +func TestPlanForExitpointStage(t *testing.T) { + const group1 string = `{"timeout": 5, "hook_sequence": [{"module_code": "foobar", "hook_impl_code": "foo"}]}` + const group2 string = `{"timeout": 10, "hook_sequence": [{"module_code": "foobar", "hook_impl_code": "bar"}, {"module_code": "ortb2blocking", "hook_impl_code": "block_request"}]}` + const group3 string = `{"timeout": 15, "hook_sequence": [{"module_code": "prebid", "hook_impl_code": "baz"}]}` + const hostPlanData string = `{"endpoints": {"/openrtb2/auction": {"stages": {"exitpoint": {"groups": [` + group1 + `]}}}}}` + const defaultAccountPlanData string = `{"endpoints": {"/openrtb2/auction": {"stages": {"exitpoint": {"groups": [` + group2 + `,` + group1 + `]}}}, "/openrtb2/amp": {"stages": {"entrypoint": {"groups": [` + group1 + `]}}}}}` + const accountPlanData string = `{"execution_plan": {"endpoints": {"/openrtb2/auction": {"stages": {"exitpoint": {"groups": [` + group3 + `]}}}}}}` + + hooks := map[string]interface{}{ + "foobar": fakeExitpointHook{}, + "ortb2blocking": fakeExitpointHook{}, + "prebid": fakeExitpointHook{}, + } + + testCases := map[string]struct { + givenEndpoint string + givenHostPlanData []byte + givenDefaultAccountPlanData []byte + giveAccountPlanData []byte + givenHooks map[string]interface{} + expectedPlan Plan[hookstage.Exitpoint] + }{ + "Account-specific execution plan rewrites default-account execution plan": { + givenEndpoint: "/openrtb2/auction", + givenHostPlanData: []byte(hostPlanData), + givenDefaultAccountPlanData: []byte(defaultAccountPlanData), + giveAccountPlanData: []byte(accountPlanData), + givenHooks: hooks, + expectedPlan: Plan[hookstage.Exitpoint]{ + // first group from host-level plan + Group[hookstage.Exitpoint]{ + Timeout: 5 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: fakeExitpointHook{}}, + }, + }, + // then come groups from account-level plan (default-account-level plan ignored) + Group[hookstage.Exitpoint]{ + Timeout: 15 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "prebid", Code: "baz", Hook: fakeExitpointHook{}}, + }, + }, + }, + }, + "Works with only account-specific plan": { + givenEndpoint: "/openrtb2/auction", + givenHostPlanData: []byte(`{}`), + givenDefaultAccountPlanData: []byte(`{}`), + giveAccountPlanData: []byte(accountPlanData), + givenHooks: hooks, + expectedPlan: Plan[hookstage.Exitpoint]{ + Group[hookstage.Exitpoint]{ + Timeout: 15 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "prebid", Code: "baz", Hook: fakeExitpointHook{}}, + }, + }, + }, + }, + "Works with empty account-specific execution plan": { + givenEndpoint: "/openrtb2/auction", + givenHostPlanData: []byte(hostPlanData), + givenDefaultAccountPlanData: []byte(defaultAccountPlanData), + giveAccountPlanData: []byte(`{}`), + givenHooks: hooks, + expectedPlan: Plan[hookstage.Exitpoint]{ + Group[hookstage.Exitpoint]{ + Timeout: 5 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: fakeExitpointHook{}}, + }, + }, + Group[hookstage.Exitpoint]{ + Timeout: 10 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "bar", Hook: fakeExitpointHook{}}, + {Module: "ortb2blocking", Code: "block_request", Hook: fakeExitpointHook{}}, + }, + }, + Group[hookstage.Exitpoint]{ + Timeout: 5 * time.Millisecond, + Hooks: []HookWrapper[hookstage.Exitpoint]{ + {Module: "foobar", Code: "foo", Hook: fakeExitpointHook{}}, + }, + }, + }, + }, + } + + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + account := new(config.Account) + if err := jsonutil.UnmarshalValid(test.giveAccountPlanData, &account.Hooks); err != nil { + t.Fatal(err) + } + + planBuilder, err := getPlanBuilder(test.givenHooks, test.givenHostPlanData, test.givenDefaultAccountPlanData) + if assert.NoError(t, err, "Failed to init hook execution plan builder") { + plan := planBuilder.PlanForExitpointStage(test.givenEndpoint, account) + assert.Equal(t, test.expectedPlan, plan) + } + }) + } +} + func getPlanBuilder( moduleHooks map[string]interface{}, hostPlanData, accountPlanData []byte, @@ -870,3 +976,13 @@ func (f fakeAuctionResponseHook) HandleAuctionResponseHook( ) (hookstage.HookResult[hookstage.AuctionResponsePayload], error) { return hookstage.HookResult[hookstage.AuctionResponsePayload]{}, nil } + +type fakeExitpointHook struct{} + +func (f fakeExitpointHook) HandleExitpointHook( + _ context.Context, + _ hookstage.ModuleInvocationContext, + _ hookstage.ExitpointPaylaod, +) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + return hookstage.HookResult[hookstage.ExitpointPaylaod]{}, nil +} diff --git a/hooks/repo.go b/hooks/repo.go index cb77c7bbea..e00077e7bc 100644 --- a/hooks/repo.go +++ b/hooks/repo.go @@ -21,6 +21,7 @@ type HookRepository interface { GetRawBidderResponseHook(id string) (hookstage.RawBidderResponse, bool) GetAllProcessedBidResponsesHook(id string) (hookstage.AllProcessedBidResponses, bool) GetAuctionResponseHook(id string) (hookstage.AuctionResponse, bool) + GetExitpointHook(id string) (hookstage.Exitpoint, bool) } // NewHookRepository returns a new instance of the HookRepository interface. @@ -49,6 +50,7 @@ type hookRepository struct { rawBidderResponseHooks map[string]hookstage.RawBidderResponse allProcessedBidResponseHooks map[string]hookstage.AllProcessedBidResponses auctionResponseHooks map[string]hookstage.AuctionResponse + exitpointHooks map[string]hookstage.Exitpoint } func (r *hookRepository) GetEntrypointHook(id string) (hookstage.Entrypoint, bool) { @@ -79,6 +81,10 @@ func (r *hookRepository) GetAuctionResponseHook(id string) (hookstage.AuctionRes return getHook(r.auctionResponseHooks, id) } +func (r *hookRepository) GetExitpointHook(id string) (hookstage.Exitpoint, bool) { + return getHook(r.exitpointHooks, id) +} + func (r *hookRepository) add(id string, hook interface{}) error { var hasAnyHooks bool var err error @@ -132,6 +138,13 @@ func (r *hookRepository) add(id string, hook interface{}) error { } } + if h, ok := hook.(hookstage.Exitpoint); ok { + hasAnyHooks = true + if r.exitpointHooks, err = addHook(r.exitpointHooks, h, id); err != nil { + return err + } + } + if !hasAnyHooks { return fmt.Errorf(`hook "%s" does not implement any supported hook interface`, id) } diff --git a/modules/helpers.go b/modules/helpers.go index c38b224931..9a3c547e0b 100644 --- a/modules/helpers.go +++ b/modules/helpers.go @@ -57,6 +57,12 @@ func createModuleStageNamesCollection(modules map[string]interface{}) (map[strin moduleStageNameCollector = addModuleStageName(moduleStageNameCollector, id, stageName) } + if _, ok := hook.(hookstage.Exitpoint); ok { + added = true + stageName := hooks.StageExitpoint.String() + moduleStageNameCollector = addModuleStageName(moduleStageNameCollector, id, stageName) + } + if !added { return nil, fmt.Errorf(`hook "%s" does not implement any supported hook interface`, id) } From 52afcade36fd0bd164af03fac4e55f7a3debcae4 Mon Sep 17 00:00:00 2001 From: Afrontio <support@afront.io> Date: Tue, 19 Aug 2025 22:19:36 +0300 Subject: [PATCH 062/272] New Adapter: Afront (#4380) --- adapters/afront/afront.go | 177 ++++++++++++++++ adapters/afront/afront_test.go | 29 +++ .../afronttest/exemplary/banner-app.json | 153 ++++++++++++++ .../afronttest/exemplary/banner-web.json | 191 ++++++++++++++++++ .../exemplary/default-host-param.json | 153 ++++++++++++++ .../afronttest/exemplary/native-app.json | 149 ++++++++++++++ .../afronttest/exemplary/native-web.json | 136 +++++++++++++ .../afronttest/exemplary/video-app.json | 162 +++++++++++++++ .../afronttest/exemplary/video-web.json | 160 +++++++++++++++ .../supplemental/empty-seatbid-array.json | 133 ++++++++++++ .../invalid-afront-ext-object.json | 29 +++ .../supplemental/invalid-response.json | 115 +++++++++++ .../supplemental/status-code-bad-request.json | 96 +++++++++ .../supplemental/status-code-no-content.json | 79 ++++++++ .../supplemental/status-code-other-error.json | 84 ++++++++ .../status-code-service-unavailable.json | 84 ++++++++ adapters/afront/params_test.go | 50 +++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_afront.go | 6 + static/bidder-info/afront.yaml | 23 +++ static/bidder-params/afront.json | 22 ++ 22 files changed, 2035 insertions(+) create mode 100644 adapters/afront/afront.go create mode 100644 adapters/afront/afront_test.go create mode 100644 adapters/afront/afronttest/exemplary/banner-app.json create mode 100644 adapters/afront/afronttest/exemplary/banner-web.json create mode 100644 adapters/afront/afronttest/exemplary/default-host-param.json create mode 100644 adapters/afront/afronttest/exemplary/native-app.json create mode 100644 adapters/afront/afronttest/exemplary/native-web.json create mode 100644 adapters/afront/afronttest/exemplary/video-app.json create mode 100644 adapters/afront/afronttest/exemplary/video-web.json create mode 100644 adapters/afront/afronttest/supplemental/empty-seatbid-array.json create mode 100644 adapters/afront/afronttest/supplemental/invalid-afront-ext-object.json create mode 100644 adapters/afront/afronttest/supplemental/invalid-response.json create mode 100644 adapters/afront/afronttest/supplemental/status-code-bad-request.json create mode 100644 adapters/afront/afronttest/supplemental/status-code-no-content.json create mode 100644 adapters/afront/afronttest/supplemental/status-code-other-error.json create mode 100644 adapters/afront/afronttest/supplemental/status-code-service-unavailable.json create mode 100644 adapters/afront/params_test.go create mode 100644 openrtb_ext/imp_afront.go create mode 100644 static/bidder-info/afront.yaml create mode 100644 static/bidder-params/afront.json diff --git a/adapters/afront/afront.go b/adapters/afront/afront.go new file mode 100644 index 0000000000..f9c41b6a1b --- /dev/null +++ b/adapters/afront/afront.go @@ -0,0 +1,177 @@ +package afront + +import ( + "fmt" + "net/http" + "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" +) + +type adapter struct { + endpoint *template.Template +} + +func Builder( + bidderName openrtb_ext.BidderName, + config config.Adapter, + server config.Server, +) ( + adapters.Bidder, + error, +) { + template, 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: template, + } + return bidder, nil +} + +func getHeaders(request *openrtb2.BidRequest) http.Header { + headers := http.Header{} + headers.Add("X-Openrtb-Version", "2.5") + headers.Add("Accept", "application/json") + headers.Add("Content-Type", "application/json;charset=utf-8") + + if request.Device != nil { + if len(request.Device.IP) > 0 { + headers.Add("X-Forwarded-For", request.Device.IP) + } + if len(request.Device.IPv6) > 0 { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + if len(request.Device.UA) > 0 { + headers.Add("User-Agent", request.Device.UA) + } + } + + return headers +} + +func (a *adapter) MakeRequests( + openRTBRequest *openrtb2.BidRequest, + reqInfo *adapters.ExtraRequestInfo, +) ( + requestsToBidder []*adapters.RequestData, + errs []error, +) { + afrontExt, err := a.getImpressionExt(&openRTBRequest.Imp[0]) + if err != nil { + return nil, []error{err} + } + + url, err := a.buildEndpointURL(afrontExt) + if err != nil { + return nil, []error{err} + } + + for idx := range openRTBRequest.Imp { + openRTBRequest.Imp[idx].Ext = nil + } + + reqJSON, err := jsonutil.Marshal(openRTBRequest) + if err != nil { + return nil, []error{err} + } + + return []*adapters.RequestData{{ + Method: http.MethodPost, + Body: reqJSON, + Uri: url, + Headers: getHeaders(openRTBRequest), + ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), + }}, nil +} + +func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtAfront, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + var afrontExt openrtb_ext.ExtAfront + if err := jsonutil.Unmarshal(bidderExt.Bidder, &afrontExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + + return &afrontExt, nil +} + +func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtAfront) (string, error) { + endpointParams := macros.EndpointTemplateParams{ + AccountID: params.AccountID, + SourceId: params.SourceId, + } + return macros.ResolveMacros(a.endpoint, endpointParams) +} + +func (a *adapter) MakeBids( + openRTBRequest *openrtb2.BidRequest, + requestToBidder *adapters.RequestData, + bidderRawResponse *adapters.ResponseData, +) ( + bidderResponse *adapters.BidderResponse, + errs []error, +) { + if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(bidderRawResponse); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(bidderRawResponse.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + if len(bidResp.SeatBid) == 0 { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Empty SeatBid array", + }} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + var bidsArray []*adapters.TypedBid + + for idx, bid := range bidResp.SeatBid[0].Bid { + bidsArray = append(bidsArray, &adapters.TypedBid{ + Bid: &bidResp.SeatBid[0].Bid[idx], + BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp), + }) + } + + bidResponse.Bids = bidsArray + return bidResponse, nil +} + +func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { + mediaType := openrtb_ext.BidTypeBanner + for _, imp := range imps { + if imp.ID == impId { + if imp.Video != nil { + mediaType = openrtb_ext.BidTypeVideo + } else if imp.Native != nil { + mediaType = openrtb_ext.BidTypeNative + } + return mediaType + } + } + return mediaType +} diff --git a/adapters/afront/afront_test.go b/adapters/afront/afront_test.go new file mode 100644 index 0000000000..8a2fde9523 --- /dev/null +++ b/adapters/afront/afront_test.go @@ -0,0 +1,29 @@ +package afront + +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/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAfront, config.Adapter{ + Endpoint: "https://snt1.afront.io/?rsd={{.SourceId}}&sk={{.AccountID}}", + }, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "afronttest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAfront, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/afront/afronttest/exemplary/banner-app.json b/adapters/afront/afronttest/exemplary/banner-app.json new file mode 100644 index 0000000000..f0f296b2db --- /dev/null +++ b/adapters/afront/afronttest/exemplary/banner-app.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } + ], + "type": "banner", + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/banner-web.json b/adapters/afront/afronttest/exemplary/banner-web.json new file mode 100644 index 0000000000..60e74c7e6f --- /dev/null +++ b/adapters/afront/afronttest/exemplary/banner-web.json @@ -0,0 +1,191 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id1", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + }, + { + "id": "some-impression-id2", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id1", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + } + }, + { + "id": "some-impression-id2", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id1", + "some-impression-id2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + }, + { + "id": "a3ae1b4e2fc24a4fb45540082e98e162", + "impid": "some-impression-id2", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } + ], + "type": "banner", + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id1", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50 + }, + "type": "banner" + }, + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e162", + "impid": "some-impression-id2", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/default-host-param.json b/adapters/afront/afronttest/exemplary/default-host-param.json new file mode 100644 index 0000000000..f0f296b2db --- /dev/null +++ b/adapters/afront/afronttest/exemplary/default-host-param.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } + ], + "type": "banner", + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/native-app.json b/adapters/afront/afronttest/exemplary/native-app.json new file mode 100644 index 0000000000..183df3f1a3 --- /dev/null +++ b/adapters/afront/afronttest/exemplary/native-app.json @@ -0,0 +1,149 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20" + } + ], + "type": "native", + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ] + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/native-web.json b/adapters/afront/afronttest/exemplary/native-web.json new file mode 100644 index 0000000000..d50816028b --- /dev/null +++ b/adapters/afront/afronttest/exemplary/native-web.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "2607:fb90:f27:4512:d800:cb23:a603:e245" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "native": { + "ver": "1.1", + "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20" + } + ], + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ] + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/video-app.json b/adapters/afront/afronttest/exemplary/video-app.json new file mode 100644 index 0000000000..09cc7f04f7 --- /dev/null +++ b/adapters/afront/afronttest/exemplary/video-app.json @@ -0,0 +1,162 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 1280, + "h": 720 + } + ], + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 1280, + "h": 720 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/exemplary/video-web.json b/adapters/afront/afronttest/exemplary/video-web.json new file mode 100644 index 0000000000..a57ce878c6 --- /dev/null +++ b/adapters/afront/afronttest/exemplary/video-web.json @@ -0,0 +1,160 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 1280, + "h": 720, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "afront" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 1280, + "h": 720, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/empty-seatbid-array.json b/adapters/afront/afronttest/supplemental/empty-seatbid-array.json new file mode 100644 index 0000000000..127c04a5b2 --- /dev/null +++ b/adapters/afront/afronttest/supplemental/empty-seatbid-array.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [], + "cur": "USD" + } + } + } + ], + "mockResponse": { + "status": 200, + "body": "invalid response" + }, + "expectedMakeBidsErrors": [ + { + "value": "Empty SeatBid array", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/invalid-afront-ext-object.json b/adapters/afront/afronttest/supplemental/invalid-afront-ext-object.json new file mode 100644 index 0000000000..77752d01ed --- /dev/null +++ b/adapters/afront/afronttest/supplemental/invalid-afront-ext-object.json @@ -0,0 +1,29 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "ext.bidder not provided", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "tagid": "my-adcode", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": "Awesome" + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [] +} diff --git a/adapters/afront/afronttest/supplemental/invalid-response.json b/adapters/afront/afronttest/supplemental/invalid-response.json new file mode 100644 index 0000000000..b3dce949f5 --- /dev/null +++ b/adapters/afront/afronttest/supplemental/invalid-response.json @@ -0,0 +1,115 @@ +{ + "mockBidRequest": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "0.0.0.0" + ] + }, + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "device": { + "ua": "test-user-agent", + "ip": "0.0.0.0", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "3998392", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/status-code-bad-request.json b/adapters/afront/afronttest/supplemental/status-code-bad-request.json new file mode 100644 index 0000000000..5a508e59ba --- /dev/null +++ b/adapters/afront/afronttest/supplemental/status-code-bad-request.json @@ -0,0 +1,96 @@ +{ + "mockBidRequest": { + "id": "req-id", + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "publisher": { + "id": "3998392" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "3998392" + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/status-code-no-content.json b/adapters/afront/afronttest/supplemental/status-code-no-content.json new file mode 100644 index 0000000000..6dde8c82b5 --- /dev/null +++ b/adapters/afront/afronttest/supplemental/status-code-no-content.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "req-id", + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/status-code-other-error.json b/adapters/afront/afronttest/supplemental/status-code-other-error.json new file mode 100644 index 0000000000..42048626a7 --- /dev/null +++ b/adapters/afront/afronttest/supplemental/status-code-other-error.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "req-id", + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 306 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 306. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/afront/afronttest/supplemental/status-code-service-unavailable.json b/adapters/afront/afronttest/supplemental/status-code-service-unavailable.json new file mode 100644 index 0000000000..5df41e0c6a --- /dev/null +++ b/adapters/afront/afronttest/supplemental/status-code-service-unavailable.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "req-id", + "tmax": 1000, + "user": { + "buyeruid": "test-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "accountId": "accountId", + "sourceId": "sourceId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://snt1.afront.io/?rsd=sourceId&sk=accountId", + "body": { + "id": "req-id", + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "3998392" + } + }, + "user": { + "buyeruid": "test-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 503 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/afront/params_test.go b/adapters/afront/params_test.go new file mode 100644 index 0000000000..b50ff16425 --- /dev/null +++ b/adapters/afront/params_test.go @@ -0,0 +1,50 @@ +package afront + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +var validParams = []string{ + `{ "sourceId": "partner", "accountId": "hash" }`, +} + +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.BidderAfront, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Afront params: %s", validParam) + } + } +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, + `{ "accountid": "" }`, +} + +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.BidderAfront, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 28303f1323..c99f2a05d7 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -36,6 +36,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/adview" "github.com/prebid/prebid-server/v3/adapters/adxcg" "github.com/prebid/prebid-server/v3/adapters/adyoulike" + "github.com/prebid/prebid-server/v3/adapters/afront" "github.com/prebid/prebid-server/v3/adapters/aidem" "github.com/prebid/prebid-server/v3/adapters/aja" "github.com/prebid/prebid-server/v3/adapters/akcelo" @@ -297,6 +298,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdView: adview.Builder, openrtb_ext.BidderAdxcg: adxcg.Builder, openrtb_ext.BidderAdyoulike: adyoulike.Builder, + openrtb_ext.BidderAfront: afront.Builder, openrtb_ext.BidderAidem: aidem.Builder, openrtb_ext.BidderAJA: aja.Builder, openrtb_ext.BidderAkcelo: akcelo.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 0e33944265..9ba2df0fae 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -52,6 +52,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdView, BidderAdxcg, BidderAdyoulike, + BidderAfront, BidderAidem, BidderAJA, BidderAkcelo, @@ -420,6 +421,7 @@ const ( BidderAdView BidderName = "adview" BidderAdxcg BidderName = "adxcg" BidderAdyoulike BidderName = "adyoulike" + BidderAfront BidderName = "afront" BidderAidem BidderName = "aidem" BidderAJA BidderName = "aja" BidderAkcelo BidderName = "akcelo" diff --git a/openrtb_ext/imp_afront.go b/openrtb_ext/imp_afront.go new file mode 100644 index 0000000000..45d692964e --- /dev/null +++ b/openrtb_ext/imp_afront.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ExtAfront struct { + AccountID string `json:"accountId"` + SourceId string `json:"sourceId"` +} diff --git a/static/bidder-info/afront.yaml b/static/bidder-info/afront.yaml new file mode 100644 index 0000000000..4a233c3ed3 --- /dev/null +++ b/static/bidder-info/afront.yaml @@ -0,0 +1,23 @@ +# Contact support@afront.io to connect with Afront exchange. +# We have the following regional endpoint sub-domains: +# US East: snt1 +# APAC: snt2 +# EU: snt3 +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +endpoint: "https://snt1.afront.io/?rsd={{.SourceId}}&sk={{.AccountID}}" +maintainer: + email: "support@afront.io" +geoscope: + - global +endpointCompression: "GZIP" +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/afront.json b/static/bidder-params/afront.json new file mode 100644 index 0000000000..c472dd3b59 --- /dev/null +++ b/static/bidder-params/afront.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Afront Adapter Params", + "description": "A schema which validates params accepted by the Afront adapter", + "type": "object", + "properties": { + "accountId": { + "type": "string", + "description": "Client account id", + "minLength": 1 + }, + "sourceId": { + "type": "string", + "description": "Data source id", + "minLength": 1 + } + }, + "required": [ + "accountId", + "sourceId" + ] +} \ No newline at end of file From 4e44ab434caec04f60405e0932c0d54eca0d6767 Mon Sep 17 00:00:00 2001 From: Scott Kay <noreply@syntaxnode.com> Date: Tue, 19 Aug 2025 15:29:26 -0400 Subject: [PATCH 063/272] Harden HTTP Response Body Handling (#4489) --- adapters/audienceNetwork/facebook.go | 8 ++-- adapters/bidder.go | 2 +- analytics/agma/sender.go | 7 ++++ analytics/pubstack/config.go | 18 +++++++- analytics/pubstack/eventchannel/sender.go | 8 +++- config/config.go | 11 +++-- currency/currency_test.go | 1 + currency/rate_converter.go | 25 ++++++++--- currency/rate_converter_test.go | 4 ++ endpoints/openrtb2/auction_benchmark_test.go | 2 +- endpoints/openrtb2/test_utils.go | 2 +- exchange/bidder.go | 26 ++++++++---- exchange/bidder_test.go | 41 ++++++++++--------- exchange/exchange_test.go | 41 ++++++++++--------- exchange/targeting_test.go | 2 +- floors/fetcher.go | 13 ++++-- main.go | 3 +- pbs/usersync.go | 11 ++++- .../backends/http_fetcher/fetcher.go | 2 + stored_requests/events/http/http.go | 1 + 20 files changed, 156 insertions(+), 72 deletions(-) diff --git a/adapters/audienceNetwork/facebook.go b/adapters/audienceNetwork/facebook.go index 2a59e3c169..dc4042412d 100644 --- a/adapters/audienceNetwork/facebook.go +++ b/adapters/audienceNetwork/facebook.go @@ -433,7 +433,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co return bidder, nil } -func (a *adapter) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, []error) { +func (a *adapter) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, error) { var ( rID string pubID string @@ -445,15 +445,13 @@ func (a *adapter) MakeTimeoutNotification(req *adapters.RequestData) (*adapters. // corresponding imp's ID rID, err = jsonparser.GetString(req.Body, "id") if err != nil { - return &adapters.RequestData{}, []error{err} + return &adapters.RequestData{}, err } // The publisher ID is expected in the app object pubID, err = jsonparser.GetString(req.Body, "app", "publisher", "id") if err != nil { - return &adapters.RequestData{}, []error{ - errors.New("path app.publisher.id not found in the request"), - } + return &adapters.RequestData{}, errors.New("path app.publisher.id not found in the request") } uri := fmt.Sprintf("https://www.facebook.com/audiencenetwork/nurl/?partner=%s&app=%s&auction=%s&ortb_loss_code=2", a.platformID, pubID, rID) diff --git a/adapters/bidder.go b/adapters/bidder.go index e4862cb2df..fb0ec07e03 100644 --- a/adapters/bidder.go +++ b/adapters/bidder.go @@ -51,7 +51,7 @@ type TimeoutBidder interface { // // Do note that if MakeRequests returns multiple requests, and more than one of these times out, MakeTimeoutNotice will be called // once for each timed out request. - MakeTimeoutNotification(req *RequestData) (*RequestData, []error) + MakeTimeoutNotification(req *RequestData) (*RequestData, error) } // BidderResponse wraps the server's response with the list of bids and the currency used by the bidder. diff --git a/analytics/agma/sender.go b/analytics/agma/sender.go index b47b059536..7ae2849a82 100644 --- a/analytics/agma/sender.go +++ b/analytics/agma/sender.go @@ -5,6 +5,7 @@ import ( "compress/gzip" "context" "fmt" + "io" "net/http" "net/url" "time" @@ -74,6 +75,12 @@ func createHttpSender(httpClient *http.Client, endpoint config.AgmaAnalyticsHttp glog.Errorf("[agmaAnalytics] Sending request failed %v", err) return err } + defer func() { + if _, err := io.Copy(io.Discard, resp.Body); err != nil { + glog.Errorf("[agmaAnalytics] Draining response body failed: %v", err) + } + resp.Body.Close() + }() if resp.StatusCode != http.StatusOK { glog.Errorf("[agmaAnalytics] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) diff --git a/analytics/pubstack/config.go b/analytics/pubstack/config.go index 3f604af58e..28330fc362 100644 --- a/analytics/pubstack/config.go +++ b/analytics/pubstack/config.go @@ -2,11 +2,14 @@ package pubstack import ( "encoding/json" + "fmt" + "io" "net/http" "net/url" "time" "github.com/docker/go-units" + "github.com/golang/glog" ) func fetchConfig(client *http.Client, endpoint *url.URL) (*Configuration, error) { @@ -14,12 +17,23 @@ func fetchConfig(client *http.Client, endpoint *url.URL) (*Configuration, error) if err != nil { return nil, err } + defer func() { + // read the entire response body to ensure full connection reuse if there's an + // error while decoding the json + if _, err := io.Copy(io.Discard, res.Body); err != nil { + glog.Errorf("[pubstack] Draining config response body failed: %v", err) + } + res.Body.Close() + }() + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code: %d", res.StatusCode) + } - defer res.Body.Close() c := Configuration{} err = json.NewDecoder(res.Body).Decode(&c) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to decode config: %w", err) } return &c, nil } diff --git a/analytics/pubstack/eventchannel/sender.go b/analytics/pubstack/eventchannel/sender.go index fe068b1555..c85c4fe446 100644 --- a/analytics/pubstack/eventchannel/sender.go +++ b/analytics/pubstack/eventchannel/sender.go @@ -3,6 +3,7 @@ package eventchannel import ( "bytes" "fmt" + "io" "net/http" "net/url" "path" @@ -27,7 +28,12 @@ func NewHttpSender(client *http.Client, endpoint string) Sender { if err != nil { return err } - resp.Body.Close() + defer func() { + if _, err := io.Copy(io.Discard, resp.Body); err != nil { + glog.Errorf("[pubstack] Draining sender response body failed: %v", err) + } + resp.Body.Close() + }() if resp.StatusCode != http.StatusOK { glog.Errorf("[pubstack] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) diff --git a/config/config.go b/config/config.go index 2716f99077..de6d04b930 100644 --- a/config/config.go +++ b/config/config.go @@ -472,15 +472,19 @@ type Analytics struct { } type CurrencyConverter struct { - FetchURL string `mapstructure:"fetch_url"` - FetchIntervalSeconds int `mapstructure:"fetch_interval_seconds"` - StaleRatesSeconds int `mapstructure:"stale_rates_seconds"` + FetchURL string `mapstructure:"fetch_url"` + FetchTimeoutMilliseconds int `mapstructure:"fetch_timeout_ms"` + FetchIntervalSeconds int `mapstructure:"fetch_interval_seconds"` + StaleRatesSeconds int `mapstructure:"stale_rates_seconds"` } func (cfg *CurrencyConverter) validate(errs []error) []error { if cfg.FetchIntervalSeconds < 0 { errs = append(errs, fmt.Errorf("currency_converter.fetch_interval_seconds must be in the range [0, %d]. Got %d", 0xffff, cfg.FetchIntervalSeconds)) } + if cfg.FetchTimeoutMilliseconds < 0 { + errs = append(errs, fmt.Errorf("currency_converter.fetch_timeout_ms must be 0 or greater. Got %d", cfg.FetchTimeoutMilliseconds)) + } return errs } @@ -1173,6 +1177,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("ccpa.enforce", false) v.SetDefault("lmt.enforce", true) v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json") + v.SetDefault("currency_converter.fetch_timeout_ms", 60000) // 60 seconds v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes v.SetDefault("currency_converter.stale_rates_seconds", 0) v.SetDefault("default_request.type", "") diff --git a/currency/currency_test.go b/currency/currency_test.go index e86ee4537f..c29c8d18e7 100644 --- a/currency/currency_test.go +++ b/currency/currency_test.go @@ -53,6 +53,7 @@ func TestGetAuctionCurrencyRates(t *testing.T) { return NewRateConverter( mockCurrencyClient, + 60*time.Second, "currency.fake.com", 24*time.Hour, ) diff --git a/currency/rate_converter.go b/currency/rate_converter.go index 2e39b57f40..d1898a59a2 100644 --- a/currency/rate_converter.go +++ b/currency/rate_converter.go @@ -1,6 +1,7 @@ package currency import ( + "context" "fmt" "io" "net/http" @@ -16,6 +17,7 @@ import ( // RateConverter holds the currencies conversion rates dictionary type RateConverter struct { httpClient httpClient + httpTimeout time.Duration staleRatesThreshold time.Duration syncSourceURL string rates atomic.Value // Should only hold Rates struct @@ -27,11 +29,13 @@ type RateConverter struct { // NewRateConverter returns a new RateConverter func NewRateConverter( httpClient httpClient, + httpTimeout time.Duration, syncSourceURL string, staleRatesThreshold time.Duration, ) *RateConverter { return &RateConverter{ httpClient: httpClient, + httpTimeout: httpTimeout, staleRatesThreshold: staleRatesThreshold, syncSourceURL: syncSourceURL, rates: atomic.Value{}, @@ -43,7 +47,10 @@ func NewRateConverter( // fetch allows to retrieve the currencies rates from the syncSourceURL provided func (rc *RateConverter) fetch() (*Rates, error) { - request, err := http.NewRequest("GET", rc.syncSourceURL, nil) + ctx, cancel := context.WithTimeout(context.Background(), rc.httpTimeout) + defer cancel() + + request, err := http.NewRequestWithContext(ctx, "GET", rc.syncSourceURL, nil) if err != nil { return nil, err } @@ -52,23 +59,29 @@ func (rc *RateConverter) fetch() (*Rates, error) { if err != nil { return nil, err } + defer func() { + // read the entire response body to ensure full connection reuse if there's an + // invalid status code + if _, err := io.Copy(io.Discard, response.Body); err != nil { + glog.Errorf("error draining conversion rates response body: %v", err) + } + response.Body.Close() + }() if response.StatusCode >= 400 { - message := fmt.Sprintf("The currency rates request failed with status code %d", response.StatusCode) + message := fmt.Sprintf("the currency rates request failed with status code %d", response.StatusCode) return nil, &errortypes.BadServerResponse{Message: message} } - defer response.Body.Close() - bytesJSON, err := io.ReadAll(response.Body) if err != nil { - return nil, err + return nil, fmt.Errorf("the currency rates request failed: %v", err) } updatedRates := &Rates{} err = jsonutil.UnmarshalValid(bytesJSON, updatedRates) if err != nil { - return nil, err + return nil, fmt.Errorf("the currency rates request failed to parse json: %v", err) } return updatedRates, err diff --git a/currency/rate_converter_test.go b/currency/rate_converter_test.go index 9504991619..0698a7ba27 100644 --- a/currency/rate_converter_test.go +++ b/currency/rate_converter_test.go @@ -123,6 +123,7 @@ func TestReadWriteRates(t *testing.T) { } currencyConverter := NewRateConverter( &http.Client{}, + 60*time.Second, url, 24*time.Hour, ) @@ -181,6 +182,7 @@ func TestRateStaleness(t *testing.T) { // Execute: currencyConverter := NewRateConverter( &http.Client{}, + 60*time.Second, mockedHttpServer.URL, 30*time.Second, // stale rates threshold ) @@ -268,6 +270,7 @@ func TestRatesAreNeverConsideredStale(t *testing.T) { // Execute: currencyConverter := NewRateConverter( &http.Client{}, + 60*time.Second, mockedHttpServer.URL, 0*time.Millisecond, // stale rates threshold ) @@ -321,6 +324,7 @@ func TestRace(t *testing.T) { interval := 1 * time.Millisecond currencyConverter := NewRateConverter( mockedHttpClient, + 60*time.Second, "currency.fake.com", 24*time.Hour, ) diff --git a/endpoints/openrtb2/auction_benchmark_test.go b/endpoints/openrtb2/auction_benchmark_test.go index 5dfaecdda9..ab8cb4863a 100644 --- a/endpoints/openrtb2/auction_benchmark_test.go +++ b/endpoints/openrtb2/auction_benchmark_test.go @@ -94,7 +94,7 @@ func BenchmarkOpenrtbEndpoint(b *testing.B) { nilMetrics, infos, gdprPermsBuilder, - currency.NewRateConverter(&http.Client{}, "", time.Duration(0)), + currency.NewRateConverter(&http.Client{}, 60*time.Second, "", time.Duration(0)), empty_fetcher.EmptyFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go index 67195d356d..bfab501682 100644 --- a/endpoints/openrtb2/test_utils.go +++ b/endpoints/openrtb2/test_utils.go @@ -1255,7 +1255,7 @@ func buildTestExchange(testCfg *testConfigValues, adapterMap map[openrtb_ext.Bid } } - mockCurrencyConverter := currency.NewRateConverter(mockCurrencyRatesServer.Client(), mockCurrencyRatesServer.URL, time.Second) + mockCurrencyConverter := currency.NewRateConverter(mockCurrencyRatesServer.Client(), time.Second, mockCurrencyRatesServer.URL, time.Second) mockCurrencyConverter.Run() gdprPermsBuilder := fakePermissionsBuilder{ diff --git a/exchange/bidder.go b/exchange/bidder.go index cd3bb36919..a305a0e84b 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -636,6 +636,7 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re err: err, } } + defer httpResp.Body.Close() respBody, err := io.ReadAll(httpResp.Body) if err != nil { @@ -644,7 +645,6 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re err: err, } } - defer httpResp.Body.Close() if httpResp.StatusCode < 200 || httpResp.StatusCode >= 400 { if httpResp.StatusCode >= 500 { @@ -671,14 +671,25 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re func (bidder *BidderAdapter) doTimeoutNotification(timeoutBidder adapters.TimeoutBidder, req *adapters.RequestData, logger util.LogMsg) { ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() - toReq, errL := timeoutBidder.MakeTimeoutNotification(req) - if toReq != nil && len(errL) == 0 { + + toReq, errMakeTimeoutNotification := timeoutBidder.MakeTimeoutNotification(req) + if toReq != nil && errMakeTimeoutNotification == nil { httpReq, err := http.NewRequest(toReq.Method, toReq.Uri, bytes.NewBuffer(toReq.Body)) if err == nil { httpReq.Header = req.Headers httpResp, err := ctxhttp.Do(ctx, bidder.Client, httpReq) + if err == nil { + defer func() { + if _, err := io.Copy(io.Discard, httpResp.Body); err != nil { + glog.Errorf("TimeoutNotification: Draining response body failed %v", err) + } + httpResp.Body.Close() + }() + } + success := (err == nil && httpResp.StatusCode >= 200 && httpResp.StatusCode < 300) bidder.me.RecordTimeoutNotice(success) + if bidder.config.Debug.TimeoutNotification.Log && !(bidder.config.Debug.TimeoutNotification.FailOnly && success) { var msg string if err == nil { @@ -697,16 +708,15 @@ func (bidder *BidderAdapter) doTimeoutNotification(timeoutBidder adapters.Timeou } } } else if bidder.config.Debug.TimeoutNotification.Log { - reqJSON, err := jsonutil.Marshal(req) + reqJSON, errMarshal := jsonutil.Marshal(req) var msg string - if err == nil { - msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request(%s)", errL[0].Error(), string(reqJSON)) + if errMarshal == nil { + msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request(%s)", errMarshal.Error(), string(reqJSON)) } else { - msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request marshal failed(%s)", errL[0].Error(), err.Error()) + msg = fmt.Sprintf("TimeoutNotification: Failed to generate timeout request: error(%s), bidder request marshal failed(%s)", errMakeTimeoutNotification.Error(), errMarshal.Error()) } util.LogRandomSample(msg, logger, bidder.config.Debug.TimeoutNotification.SamplingRate) } - } type httpCallInfo struct { diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index dbb167e053..50e919c2a6 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -104,7 +104,7 @@ func TestSingleBidder(t *testing.T) { bidderImpl.bidResponse = mockBidderResponse bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, test.debugInfo, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -229,7 +229,7 @@ func TestSingleBidderGzip(t *testing.T) { bidderImpl.bidResponse = mockBidderResponse bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, test.debugInfo, "GZIP") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -330,7 +330,7 @@ func TestRequestBidRemovesSensitiveHeaders(t *testing.T) { ctx := context.Background() bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -384,7 +384,7 @@ func TestSetGPCHeader(t *testing.T) { ctx := context.Background() bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, BidderName: "test", @@ -435,7 +435,7 @@ func TestSetGPCHeaderNil(t *testing.T) { ctx := context.Background() bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -508,7 +508,7 @@ func TestMultiBidder(t *testing.T) { bidResponse: mockBidderResponse, } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, BidderName: "test", @@ -877,6 +877,7 @@ func TestMultiCurrencies(t *testing.T) { bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") currencyConverter := currency.NewRateConverter( &http.Client{}, + 60*time.Second, mockedHTTPServer.URL, time.Duration(24)*time.Hour, ) @@ -1043,7 +1044,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) { // Execute: bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, BidderName: "test", @@ -1221,6 +1222,7 @@ func TestMultiCurrencies_RequestCurrencyPick(t *testing.T) { bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") currencyConverter := currency.NewRateConverter( &http.Client{}, + 60*time.Second, mockedHTTPServer.URL, time.Duration(24)*time.Hour, ) @@ -1541,7 +1543,7 @@ func TestMobileNativeTypes(t *testing.T) { bidResponse: tc.mockBidderResponse, } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: tc.mockBidderRequest, @@ -1699,7 +1701,7 @@ func TestRequestBidsStoredBidResponses(t *testing.T) { bidderImpl := &goodSingleBidderWithStoredBidResp{} bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: tc.mockBidderRequest, @@ -1805,7 +1807,7 @@ func TestFledge(t *testing.T) { bidResponses: tc.mockBidderResponse, } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderOpenx, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{ @@ -1851,7 +1853,7 @@ func TestFledge(t *testing.T) { func TestErrorReporting(t *testing.T) { bidder := AdaptBidder(&bidRejector{}, nil, &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, BidderName: "test", @@ -2086,7 +2088,7 @@ func TestCallRecordAdapterConnections(t *testing.T) { // Run requestBid using an http.Client with a mock handler bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, mockMetricEngine, openrtb_ext.BidderAppnexus, nil, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2333,7 +2335,7 @@ func TestRequestBidsWithAdsCertsSigner(t *testing.T) { } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{Allow: false}, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2473,7 +2475,7 @@ func (bidder *notifyingBidder) MakeBids(internalRequest *openrtb2.BidRequest, ex return nil, nil } -func (bidder *notifyingBidder) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, []error) { +func (bidder *notifyingBidder) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, error) { return &bidder.notifyRequest, nil } @@ -2541,7 +2543,7 @@ func TestExtraBid(t *testing.T) { } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{}, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2655,7 +2657,7 @@ func TestExtraBidWithAlternateBidderCodeDisabled(t *testing.T) { } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{}, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2761,7 +2763,7 @@ func TestExtraBidWithBidAdjustments(t *testing.T) { } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{}, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2874,7 +2876,7 @@ func TestExtraBidWithBidAdjustmentsUsingAdapterCode(t *testing.T) { } bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{}, "") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) bidderReq := BidderRequest{ BidRequest: &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "impId"}}}, @@ -2996,6 +2998,7 @@ func TestExtraBidWithMultiCurrencies(t *testing.T) { bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, openrtb_ext.BidderAppnexus, nil, "") currencyConverter := currency.NewRateConverter( &http.Client{}, + 60*time.Second, mockedHTTPServer.URL, time.Duration(24)*time.Hour, ) @@ -3267,7 +3270,7 @@ func TestUpdateBidderTmax(t *testing.T) { requestHeaders := http.Header{} requestHeaders.Add("Content-Type", "application/json") - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) var requestTmax int64 = 700 bidderReq := BidderRequest{ diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index 4756f5b4b6..d86f1b33bc 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -76,7 +76,7 @@ func TestNewExchange(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) gdprPermsBuilder := fakePermissionsBuilder{ permissions: &permissionsMock{ @@ -126,7 +126,7 @@ func TestCharacterEscape(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) gdprPermsBuilder := fakePermissionsBuilder{ permissions: &permissionsMock{ @@ -333,7 +333,7 @@ func TestDebugBehaviour(t *testing.T) { allowAllBidders: true, }, }.Builder - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.categoriesFetcher = categoriesFetcher e.requestSplitter = requestSplitter{ me: &metricsConf.NilMetricsEngine{}, @@ -499,7 +499,7 @@ func TestTwoBiddersDebugDisabledAndEnabled(t *testing.T) { allowAllBidders: true, }, }.Builder - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.categoriesFetcher = categoriesFetcher e.requestSplitter = requestSplitter{ me: e.me, @@ -581,6 +581,7 @@ func TestOverrideWithCustomCurrency(t *testing.T) { } mockCurrencyConverter := currency.NewRateConverter( mockCurrencyClient, + 60*time.Second, "currency.fake.com", 24*time.Hour, ) @@ -748,6 +749,7 @@ func TestAdapterCurrency(t *testing.T) { } currencyConverter := currency.NewRateConverter( mockCurrencyClient, + 60*time.Second, "currency.fake.com", 24*time.Hour, ) @@ -832,6 +834,7 @@ func TestFloorsSignalling(t *testing.T) { } currencyConverter := currency.NewRateConverter( mockCurrencyClient, + 60*time.Second, "currency.com", 24*time.Hour, ) @@ -1130,7 +1133,7 @@ func TestReturnCreativeEndToEnd(t *testing.T) { allowAllBidders: true, }, }.Builder - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.categoriesFetcher = categoriesFetcher e.bidIDGenerator = &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false} e.requestSplitter = requestSplitter{ @@ -1228,7 +1231,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) { if adaptersErr != nil { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) pbc := pbc.NewClient(&http.Client{}, &cfg.CacheURL, &cfg.ExtCacheURL, testEngine) gdprPermsBuilder := fakePermissionsBuilder{ @@ -1429,7 +1432,7 @@ func TestBidReturnsCreative(t *testing.T) { e.cache = &wellBehavedCache{} e.me = &metricsConf.NilMetricsEngine{} - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) //Run tests for _, test := range testCases { @@ -1588,7 +1591,7 @@ func TestBidResponseCurrency(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) gdprPermsBuilder := fakePermissionsBuilder{ permissions: &permissionsMock{ @@ -1820,7 +1823,7 @@ func TestRaceIntegration(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) auctionRequest := &AuctionRequest{ BidRequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: getTestBuildRequest(t)}, @@ -1928,7 +1931,7 @@ func TestPanicRecovery(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) gdprPermsBuilder := fakePermissionsBuilder{ permissions: &permissionsMock{ @@ -1994,7 +1997,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) categoriesFetcher, error := newCategoryFetcher("./test/category-mapping") if error != nil { @@ -2466,7 +2469,7 @@ func newExchangeForTests(t *testing.T, filename string, aliases map[string]strin me: metricsEngine, cache: &wellBehavedCache{}, cacheTime: 0, - currencyConverter: currency.NewRateConverter(&http.Client{}, "", time.Duration(0)), + currencyConverter: currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)), gdprDefaultValue: gdprDefaultValue, gdprPermsBuilder: gdprPermsBuilder, privacyConfig: privacyConfig, @@ -4142,7 +4145,7 @@ func TestStoredAuctionResponses(t *testing.T) { e.me = &metricsConf.NilMetricsEngine{} e.categoriesFetcher = categoriesFetcher e.bidIDGenerator = &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false} - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.gdprPermsBuilder = fakePermissionsBuilder{ permissions: &permissionsMock{ allowAllBidders: true, @@ -4508,7 +4511,7 @@ func TestAuctionDebugEnabled(t *testing.T) { e.me = &metricsConf.NilMetricsEngine{} e.categoriesFetcher = categoriesFetcher e.bidIDGenerator = &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false} - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.gdprPermsBuilder = fakePermissionsBuilder{ permissions: &permissionsMock{ allowAllBidders: true, @@ -4576,7 +4579,7 @@ func TestPassExperimentConfigsToHoldAuction(t *testing.T) { t.Fatalf("Error intializing adapters: %v", adaptersErr) } - currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) gdprPermsBuilder := fakePermissionsBuilder{ permissions: &permissionsMock{ @@ -4909,7 +4912,7 @@ func TestMakeBidWithValidation(t *testing.T) { e.cache = &wellBehavedCache{} e.me = &metricsConf.NilMetricsEngine{} - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) ImpExtInfoMap := make(map[string]ImpExtInfo) ImpExtInfoMap["1"] = ImpExtInfo{} @@ -5105,7 +5108,7 @@ func TestOverrideConfigAlternateBidderCodesWithRequestValues(t *testing.T) { allowAllBidders: true, }, }.Builder - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.categoriesFetcher = categoriesFetcher e.bidIDGenerator = &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false} e.requestSplitter = requestSplitter{ @@ -5890,7 +5893,7 @@ func TestModulesCanBeExecutedForMultipleBiddersSimultaneously(t *testing.T) { e := new(exchange) e.me = &metricsConf.NilMetricsEngine{} - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.requestSplitter = requestSplitter{ me: e.me, gdprPermsBuilder: e.gdprPermsBuilder, @@ -6637,7 +6640,7 @@ func TestAmpEnv(t *testing.T) { allowAllBidders: true, }, }.Builder - e.currencyConverter = currency.NewRateConverter(&http.Client{}, "", time.Duration(0)) + e.currencyConverter = currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) e.categoriesFetcher = categoriesFetcher e.requestSplitter = requestSplitter{ me: &metricsConf.NilMetricsEngine{}, diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index d798f22e9b..b3aa91de53 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -144,7 +144,7 @@ func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*op cache: &wellBehavedCache{}, cacheTime: time.Duration(0), gdprPermsBuilder: gdprPermsBuilder, - currencyConverter: currency.NewRateConverter(&http.Client{}, "", time.Duration(0)), + currencyConverter: currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)), gdprDefaultValue: gdpr.SignalYes, categoriesFetcher: categoriesFetcher, bidIDGenerator: &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false}, diff --git a/floors/fetcher.go b/floors/fetcher.go index 9fa6ad4f38..c48b45fd7a 100644 --- a/floors/fetcher.go +++ b/floors/fetcher.go @@ -238,13 +238,13 @@ func (f *PriceFloorFetcher) fetchAndValidate(config config.AccountFloorFetch) (* } if len(floorResp) > (config.MaxFileSizeKB * 1024) { - glog.Errorf("Recieved invalid floor data from URL: %s, reason : floor file size is greater than MaxFileSize", config.URL) + glog.Errorf("Received invalid floor data from URL: %s, reason : floor file size is greater than MaxFileSize", config.URL) return nil, 0 } var priceFloors openrtb_ext.PriceFloorRules if err = json.Unmarshal(floorResp, &priceFloors.Data); err != nil { - glog.Errorf("Recieved invalid price floor json from URL: %s", config.URL) + glog.Errorf("Received invalid price floor json from URL: %s", config.URL) return nil, 0 } @@ -271,6 +271,14 @@ func (f *PriceFloorFetcher) fetchFloorRulesFromURL(config config.AccountFloorFet if err != nil { return nil, 0, errors.New("error while getting response from url : " + err.Error()) } + defer func() { + // read the entire response body to ensure full connection reuse if there's an + // invalid status code + if _, err := io.Copy(io.Discard, httpResp.Body); err != nil { + glog.Errorf("error while draining fetched floor response body: %v", err) + } + httpResp.Body.Close() + }() if httpResp.StatusCode != http.StatusOK { return nil, 0, errors.New("no response from server") @@ -291,7 +299,6 @@ func (f *PriceFloorFetcher) fetchFloorRulesFromURL(config config.AccountFloorFet if err != nil { return nil, 0, errors.New("unable to read response") } - defer httpResp.Body.Close() return respBody, maxAge, nil } diff --git a/main.go b/main.go index 0063b4ee0b..5e0f5cfd33 100644 --- a/main.go +++ b/main.go @@ -65,9 +65,10 @@ func loadConfig(bidderInfos config.BidderInfos) (*config.Configuration, error) { } func serve(cfg *config.Configuration) error { + httpTimeout := time.Duration(cfg.CurrencyConverter.FetchTimeoutMilliseconds) * time.Millisecond fetchingInterval := time.Duration(cfg.CurrencyConverter.FetchIntervalSeconds) * time.Second staleRatesThreshold := time.Duration(cfg.CurrencyConverter.StaleRatesSeconds) * time.Second - currencyConverter := currency.NewRateConverter(&http.Client{}, cfg.CurrencyConverter.FetchURL, staleRatesThreshold) + currencyConverter := currency.NewRateConverter(&http.Client{}, httpTimeout, cfg.CurrencyConverter.FetchURL, staleRatesThreshold) currencyConverterTickerTask := task.NewTickerTask(fetchingInterval, currencyConverter) currencyConverterTickerTask.Start() diff --git a/pbs/usersync.go b/pbs/usersync.go index b8c0572c4a..bde61a7cbd 100644 --- a/pbs/usersync.go +++ b/pbs/usersync.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "io" "net/http" "net/url" "strings" @@ -45,7 +46,15 @@ func (deps *UserSyncDeps) VerifyRecaptcha(response string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + // read the entire response body to ensure full connection reuse if there's an + // error while decoding the json + if _, err := io.Copy(io.Discard, resp.Body); err != nil { + glog.Errorf("Captcha verify draining response body failed: %v", err) + } + resp.Body.Close() + }() + var gr = googleResponse{} if err := json.NewDecoder(resp.Body).Decode(&gr); err != nil { return err diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go index a261fb6bdf..5dff2fddba 100644 --- a/stored_requests/backends/http_fetcher/fetcher.go +++ b/stored_requests/backends/http_fetcher/fetcher.go @@ -92,6 +92,7 @@ func (fetcher *HttpFetcher) FetchRequests(ctx context.Context, requestIDs []stri return nil, nil, []error{err} } defer httpResp.Body.Close() + requestData, impData, errs = unpackResponse(httpResp) return } @@ -142,6 +143,7 @@ func (fetcher *HttpFetcher) FetchAccounts(ctx context.Context, accountIDs []stri } } defer httpResp.Body.Close() + respBytes, err := io.ReadAll(httpResp.Body) if err != nil { return nil, []error{ diff --git a/stored_requests/events/http/http.go b/stored_requests/events/http/http.go index 6ea41a6f84..ec17bd0773 100644 --- a/stored_requests/events/http/http.go +++ b/stored_requests/events/http/http.go @@ -96,6 +96,7 @@ type HTTPEvents struct { func (e *HTTPEvents) fetchAll() { ctx, cancel := e.ctxProducer() defer cancel() + resp, err := ctxhttp.Get(ctx, e.client, e.Endpoint) if respObj, ok := e.parse(e.Endpoint, resp, err); ok && (len(respObj.StoredRequests) > 0 || len(respObj.StoredImps) > 0 || len(respObj.StoredResponses) > 0 || len(respObj.Accounts) > 0) { From c6bf80ca6e8628455b165ffc764f19ebb6b67a88 Mon Sep 17 00:00:00 2001 From: MaksymTeqBlaze <maksym.pavliv@teqblaze.com> Date: Thu, 21 Aug 2025 17:57:38 +0300 Subject: [PATCH 064/272] New Adapter: TeqBlaze (#4480) --- adapters/teqblaze/params_test.go | 49 ++++ adapters/teqblaze/teqblaze.go | 153 +++++++++++ adapters/teqblaze/teqblaze_test.go | 20 ++ .../teqblazetest/exemplary/banner.json | 136 ++++++++++ .../teqblazetest/exemplary/endpoint_id.json | 136 ++++++++++ .../teqblazetest/exemplary/multi_format.json | 105 ++++++++ .../teqblazetest/exemplary/multi_imp.json | 249 ++++++++++++++++++ .../teqblazetest/exemplary/native.json | 120 +++++++++ .../teqblazetest/exemplary/video.json | 131 +++++++++ .../teqblazetest/exemplary/web_banner.json | 136 ++++++++++ .../supplemental/bad_ext_bidder.json | 40 +++ .../supplemental/bad_imp_ext.json | 38 +++ .../supplemental/bad_media_type.json | 83 ++++++ .../supplemental/bad_response.json | 85 ++++++ .../teqblazetest/supplemental/status_204.json | 80 ++++++ .../supplemental/status_not_200.json | 85 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_teqblaze.go | 6 + static/bidder-info/teqblaze.yaml | 14 + static/bidder-params/teqblaze.json | 22 ++ 21 files changed, 1692 insertions(+) create mode 100644 adapters/teqblaze/params_test.go create mode 100644 adapters/teqblaze/teqblaze.go create mode 100644 adapters/teqblaze/teqblaze_test.go create mode 100644 adapters/teqblaze/teqblazetest/exemplary/banner.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/endpoint_id.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/multi_format.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/multi_imp.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/native.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/video.json create mode 100644 adapters/teqblaze/teqblazetest/exemplary/web_banner.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/bad_ext_bidder.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/bad_imp_ext.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/bad_media_type.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/bad_response.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/status_204.json create mode 100644 adapters/teqblaze/teqblazetest/supplemental/status_not_200.json create mode 100644 openrtb_ext/imp_teqblaze.go create mode 100644 static/bidder-info/teqblaze.yaml create mode 100644 static/bidder-params/teqblaze.json diff --git a/adapters/teqblaze/params_test.go b/adapters/teqblaze/params_test.go new file mode 100644 index 0000000000..2c86ea1485 --- /dev/null +++ b/adapters/teqblaze/params_test.go @@ -0,0 +1,49 @@ +package teqblaze + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderTeqBlaze, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderTeqBlaze, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"placementId": "test"}`, + `{"placementId": "1"}`, + `{"endpointId": "test"}`, + `{"endpointId": "1"}`, +} + +var invalidParams = []string{ + `{"placementId": 42}`, + `{"endpointId": 42}`, + `{"placementId": "1", "endpointId": "1"}`, + `{"placementId": ""}`, + `{"endpointId": ""}`, +} diff --git a/adapters/teqblaze/teqblaze.go b/adapters/teqblaze/teqblaze.go new file mode 100644 index 0000000000..b6e391bb85 --- /dev/null +++ b/adapters/teqblaze/teqblaze.go @@ -0,0 +1,153 @@ +package teqblaze + +import ( + "fmt" + "net/http" + + "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/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type reqBodyExt struct { + TeqBlazeBidderExt reqBodyExtBidder `json:"bidder"` +} + +type reqBodyExtBidder struct { + Type string `json:"type"` + PlacementID string `json:"placementId,omitempty"` + EndpointID string `json:"endpointId,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) { + var errs []error + var adapterRequests []*adapters.RequestData + + reqCopy := *request + for _, imp := range request.Imp { + reqCopy.Imp = []openrtb2.Imp{imp} + + var bidderExt adapters.ExtImpBidder + var teqblazeExt openrtb_ext.ImpExtTeqBlaze + + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + errs = append(errs, err) + continue + } + if err := jsonutil.Unmarshal(bidderExt.Bidder, &teqblazeExt); err != nil { + errs = append(errs, err) + continue + } + + impExt := reqBodyExt{TeqBlazeBidderExt: reqBodyExtBidder{}} + + if teqblazeExt.PlacementID != "" { + impExt.TeqBlazeBidderExt.PlacementID = teqblazeExt.PlacementID + impExt.TeqBlazeBidderExt.Type = "publisher" + } else if teqblazeExt.EndpointID != "" { + impExt.TeqBlazeBidderExt.EndpointID = teqblazeExt.EndpointID + impExt.TeqBlazeBidderExt.Type = "network" + } + + impExtJSON, err := jsonutil.Marshal(impExt) + if err != nil { + errs = append(errs, err) + continue + } + + reqCopy.Imp[0].Ext = impExtJSON + + adapterReq, err := a.makeRequest(&reqCopy) + if err != nil { + errs = append(errs, err) + continue + } + + adapterRequests = append(adapterRequests, adapterReq) + } + + return adapterRequests, errs +} + +func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) { + reqJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + return &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if len(response.Cur) != 0 { + bidResponse.Currency = response.Cur + } + + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bid := seatBid.Bid[i] + bidType, err := getBidType(bid) + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + // determinate media type by bid response field mtype + 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 + default: + return "", fmt.Errorf("could not define media type for bid: %s", bid.ImpID) + } +} diff --git a/adapters/teqblaze/teqblaze_test.go b/adapters/teqblaze/teqblaze_test.go new file mode 100644 index 0000000000..f4a3cdca92 --- /dev/null +++ b/adapters/teqblaze/teqblaze_test.go @@ -0,0 +1,20 @@ +package teqblaze + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderTeqBlaze, config.Adapter{ + Endpoint: "https://fake.test.io/pserver"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "teqblazetest", bidder) +} diff --git a/adapters/teqblaze/teqblazetest/exemplary/banner.json b/adapters/teqblaze/teqblazetest/exemplary/banner.json new file mode 100644 index 0000000000..fb227c20e7 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/banner.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/exemplary/endpoint_id.json b/adapters/teqblaze/teqblazetest/exemplary/endpoint_id.json new file mode 100644 index 0000000000..f9587f39c3 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/endpoint_id.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/teqblaze/teqblazetest/exemplary/multi_format.json b/adapters/teqblaze/teqblazetest/exemplary/multi_format.json new file mode 100644 index 0000000000..fbb70682fa --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/multi_format.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/teqblaze/teqblazetest/exemplary/multi_imp.json b/adapters/teqblaze/teqblazetest/exemplary/multi_imp.json new file mode 100644 index 0000000000..f5c1e687eb --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/multi_imp.json @@ -0,0 +1,249 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + }, + { + "id": "test-imp-id-1", + "tagid": "test-1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "tagid": "test-1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id-1", + "price": 0.27543, + "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id-1", + "price": 0.27543, + "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/exemplary/native.json b/adapters/teqblaze/teqblazetest/exemplary/native.json new file mode 100644 index 0000000000..87e77e1af0 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/native.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/exemplary/video.json b/adapters/teqblaze/teqblazetest/exemplary/video.json new file mode 100644 index 0000000000..aa2ae042e1 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/video.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ] + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/teqblaze/teqblazetest/exemplary/web_banner.json b/adapters/teqblaze/teqblazetest/exemplary/web_banner.json new file mode 100644 index 0000000000..f3c41c0049 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/exemplary/web_banner.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Ubuntu" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Ubuntu" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/supplemental/bad_ext_bidder.json b/adapters/teqblaze/teqblazetest/supplemental/bad_ext_bidder.json new file mode 100644 index 0000000000..5dcfdb89fd --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/bad_ext_bidder.json @@ -0,0 +1,40 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": 123 + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found 1", + "comparison": "literal" + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/supplemental/bad_imp_ext.json b/adapters/teqblaze/teqblazetest/supplemental/bad_imp_ext.json new file mode 100644 index 0000000000..b87e5074d0 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/bad_imp_ext.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": 123 + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found 1", + "comparison": "literal" + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/supplemental/bad_media_type.json b/adapters/teqblaze/teqblazetest/supplemental/bad_media_type.json new file mode 100644 index 0000000000..1d16a6f94c --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/bad_media_type.json @@ -0,0 +1,83 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://fake.test.io/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": {} + } + ], + "seat": "teqblaze" + } + ], + "cur": "USD" + } + } + }], + "expectedMakeBidsErrors": [ + { + "value": "could not define media type for bid: test-imp-id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/teqblaze/teqblazetest/supplemental/bad_response.json b/adapters/teqblaze/teqblazetest/supplemental/bad_response.json new file mode 100644 index 0000000000..4fe8d572c4 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/bad_response.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + }], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/teqblaze/teqblazetest/supplemental/status_204.json b/adapters/teqblaze/teqblazetest/supplemental/status_204.json new file mode 100644 index 0000000000..f72a2eb060 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/status_204.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} diff --git a/adapters/teqblaze/teqblazetest/supplemental/status_not_200.json b/adapters/teqblaze/teqblazetest/supplemental/status_not_200.json new file mode 100644 index 0000000000..218aa63261 --- /dev/null +++ b/adapters/teqblaze/teqblazetest/supplemental/status_not_200.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 404, + "body": {} + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index c99f2a05d7..fa1ea996f2 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -224,6 +224,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/tappx" "github.com/prebid/prebid-server/v3/adapters/teads" "github.com/prebid/prebid-server/v3/adapters/telaria" + "github.com/prebid/prebid-server/v3/adapters/teqblaze" "github.com/prebid/prebid-server/v3/adapters/theadx" "github.com/prebid/prebid-server/v3/adapters/thetradedesk" "github.com/prebid/prebid-server/v3/adapters/tpmn" @@ -489,6 +490,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderTappx: tappx.Builder, openrtb_ext.BidderTeads: teads.Builder, openrtb_ext.BidderTelaria: telaria.Builder, + openrtb_ext.BidderTeqBlaze: teqblaze.Builder, openrtb_ext.BidderTheadx: theadx.Builder, openrtb_ext.BidderTheTradeDesk: thetradedesk.Builder, openrtb_ext.BidderTpmn: tpmn.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 9ba2df0fae..c9f3fa6017 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -242,6 +242,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderTappx, BidderTeads, BidderTelaria, + BidderTeqBlaze, BidderTheadx, BidderTheTradeDesk, BidderTpmn, @@ -611,6 +612,7 @@ const ( BidderTappx BidderName = "tappx" BidderTeads BidderName = "teads" BidderTelaria BidderName = "telaria" + BidderTeqBlaze BidderName = "teqblaze" BidderTheadx BidderName = "theadx" BidderTheTradeDesk BidderName = "thetradedesk" BidderTpmn BidderName = "tpmn" diff --git a/openrtb_ext/imp_teqblaze.go b/openrtb_ext/imp_teqblaze.go new file mode 100644 index 0000000000..bcd7779ef8 --- /dev/null +++ b/openrtb_ext/imp_teqblaze.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtTeqBlaze struct { + PlacementID string `json:"placementId"` + EndpointID string `json:"endpointId"` +} diff --git a/static/bidder-info/teqblaze.yaml b/static/bidder-info/teqblaze.yaml new file mode 100644 index 0000000000..f282df3246 --- /dev/null +++ b/static/bidder-info/teqblaze.yaml @@ -0,0 +1,14 @@ +whiteLabelOnly: true +maintainer: + email: "github@teqblaze.com" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/teqblaze.json b/static/bidder-params/teqblaze.json new file mode 100644 index 0000000000..2d0994c786 --- /dev/null +++ b/static/bidder-params/teqblaze.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TeqBlaze Adapter Params", + "description": "A schema which validates params accepted by the TeqBlaze adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "Placement ID" + }, + "endpointId": { + "type": "string", + "minLength": 1, + "description": "Endpoint ID" + } + }, + "oneOf": [ + { "required": ["placementId"] }, + { "required": ["endpointId"] } + ] +} \ No newline at end of file From bd3f8d5759bb40ed0ded2d52041778bcc888fbce Mon Sep 17 00:00:00 2001 From: "esimonelli@onetag" <136568337+EmanueleSimonelli@users.noreply.github.com> Date: Mon, 25 Aug 2025 21:45:54 +0200 Subject: [PATCH 065/272] Onetag: imp.ext read generalization (#4446) Co-authored-by: lorenzob <l.baglini@onetag.com> --- adapters/onetag/onetag.go | 3 +- .../onetag/onetagtest/exemplary/no-bid.json | 5 ++ .../onetagtest/exemplary/simple-banner.json | 16 ++++- .../onetagtest/exemplary/simple-native.json | 7 +- .../onetagtest/exemplary/simple-video.json | 5 ++ .../onetagtest/exemplary/with-gpid.json | 67 +++++++++++++++++++ .../supplemental/internal-server-error.json | 5 ++ .../supplemental/wrong-impression-id.json | 7 +- 8 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 adapters/onetag/onetagtest/exemplary/with-gpid.json diff --git a/adapters/onetag/onetag.go b/adapters/onetag/onetag.go index c0972816e6..d1b2e6238e 100644 --- a/adapters/onetag/onetag.go +++ b/adapters/onetag/onetag.go @@ -34,7 +34,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { pubID := "" - for idx, imp := range request.Imp { + for _, imp := range request.Imp { onetagExt, err := getImpressionExt(imp) if err != nil { return nil, []error{err} @@ -52,7 +52,6 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte Message: "The publisher ID must not be empty", }} } - request.Imp[idx].Ext = onetagExt.Ext } url, err := a.buildEndpointURL(pubID) diff --git a/adapters/onetag/onetagtest/exemplary/no-bid.json b/adapters/onetag/onetagtest/exemplary/no-bid.json index 091d329a4c..9aaaa4052d 100644 --- a/adapters/onetag/onetagtest/exemplary/no-bid.json +++ b/adapters/onetag/onetagtest/exemplary/no-bid.json @@ -63,6 +63,11 @@ ], "w": 1024, "h": 576 + }, + "ext": { + "bidder": { + "pubId": "386276e072" + } } } ] diff --git a/adapters/onetag/onetagtest/exemplary/simple-banner.json b/adapters/onetag/onetagtest/exemplary/simple-banner.json index 2484523652..0961775782 100644 --- a/adapters/onetag/onetagtest/exemplary/simple-banner.json +++ b/adapters/onetag/onetagtest/exemplary/simple-banner.json @@ -74,7 +74,12 @@ "w": 300, "pos": 1 }, - "bidfloor": 0.05 + "bidfloor": 0.05, + "ext": { + "bidder": { + "pubId": "386276e072" + } + } }, { "id": "121-dt2", @@ -85,8 +90,13 @@ }, "bidfloor": 0.12, "ext": { - "key1": "value1", - "key2": "value2" + "bidder": { + "pubId": "386276e072", + "ext": { + "key1": "value1", + "key2": "value2" + } + } } } ], diff --git a/adapters/onetag/onetagtest/exemplary/simple-native.json b/adapters/onetag/onetagtest/exemplary/simple-native.json index c7a499d82c..4ccf18f310 100644 --- a/adapters/onetag/onetagtest/exemplary/simple-native.json +++ b/adapters/onetag/onetagtest/exemplary/simple-native.json @@ -56,7 +56,12 @@ "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" }, "ext": { - "key1": "value1" + "bidder": { + "pubId": "386276e072", + "ext": { + "key1": "value1" + } + } } } ], diff --git a/adapters/onetag/onetagtest/exemplary/simple-video.json b/adapters/onetag/onetagtest/exemplary/simple-video.json index 73b830aa26..4cf0ac2295 100644 --- a/adapters/onetag/onetagtest/exemplary/simple-video.json +++ b/adapters/onetag/onetagtest/exemplary/simple-video.json @@ -63,6 +63,11 @@ ], "w": 1024, "h": 576 + }, + "ext": { + "bidder": { + "pubId": "386276e072" + } } } ] diff --git a/adapters/onetag/onetagtest/exemplary/with-gpid.json b/adapters/onetag/onetagtest/exemplary/with-gpid.json new file mode 100644 index 0000000000..d347da1f1c --- /dev/null +++ b/adapters/onetag/onetagtest/exemplary/with-gpid.json @@ -0,0 +1,67 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "gpid": "test-gpid", + "bidder": { + "pubId": "386276e072" + } + } + } + ], + "site": { + "id": "test-site-id" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/prebid-server/386276e072", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "gpid": "test-gpid", + "bidder": { + "pubId": "386276e072" + } + } + } + ], + "site": { + "id": "test-site-id" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/onetag/onetagtest/supplemental/internal-server-error.json b/adapters/onetag/onetagtest/supplemental/internal-server-error.json index fd7a2385b5..7d41919e58 100644 --- a/adapters/onetag/onetagtest/supplemental/internal-server-error.json +++ b/adapters/onetag/onetagtest/supplemental/internal-server-error.json @@ -63,6 +63,11 @@ ], "w": 1024, "h": 576 + }, + "ext": { + "bidder": { + "pubId": "386276e072" + } } } ] diff --git a/adapters/onetag/onetagtest/supplemental/wrong-impression-id.json b/adapters/onetag/onetagtest/supplemental/wrong-impression-id.json index a8da8949b1..495e979e2d 100644 --- a/adapters/onetag/onetagtest/supplemental/wrong-impression-id.json +++ b/adapters/onetag/onetagtest/supplemental/wrong-impression-id.json @@ -56,7 +56,12 @@ "w": 300, "pos": 1 }, - "bidfloor": 0.05 + "bidfloor": 0.05, + "ext": { + "bidder": { + "pubId": "386276e072" + } + } } ], "site": { From e4d9ac4ac1df8d2c72e97e727d11ab63dd069998 Mon Sep 17 00:00:00 2001 From: Veronika Solovei <kalypsonika@gmail.com> Date: Mon, 25 Aug 2025 15:58:20 -0400 Subject: [PATCH 066/272] Rules Engine Module: Configurable cache update frequency (#4423) Co-authored-by: VeronikaSolovei9 <vsolovei@microsoft.com> --- modules/prebid/rulesengine/cache.go | 23 ++- modules/prebid/rulesengine/cache_test.go | 50 ++++++- modules/prebid/rulesengine/module.go | 47 +++--- modules/prebid/rulesengine/module_test.go | 137 +++++++++++------- modules/prebid/rulesengine/tree_manager.go | 2 +- .../prebid/rulesengine/tree_manager_test.go | 4 +- 6 files changed, 184 insertions(+), 79 deletions(-) diff --git a/modules/prebid/rulesengine/cache.go b/modules/prebid/rulesengine/cache.go index f1fb1faaca..1b09abc1c5 100644 --- a/modules/prebid/rulesengine/cache.go +++ b/modules/prebid/rulesengine/cache.go @@ -3,6 +3,9 @@ package rulesengine import ( "sync" "sync/atomic" + "time" + + "github.com/prebid/prebid-server/v3/util/timeutil" ) type accountID = string @@ -11,20 +14,34 @@ type cacher interface { Get(string) *cacheEntry Set(string, *cacheEntry) Delete(id accountID) + Expired(time.Time) bool } type cache struct { sync.Mutex - m atomic.Value + m atomic.Value + refreshFrequency time.Duration + t timeutil.Time } -func NewCache() *cache { +func NewCache(refreshRateSeconds int) *cache { var atomicMap atomic.Value atomicMap.Store(make(map[accountID]*cacheEntry)) return &cache{ - m: atomicMap, + m: atomicMap, + refreshFrequency: time.Duration(refreshRateSeconds) * time.Second, + t: &timeutil.RealTime{}, + } +} + +func (c *cache) Expired(coTimestamp time.Time) bool { + if c.refreshFrequency <= 0 { + return false } + currentTime := c.t.Now() + delta := currentTime.Sub(coTimestamp) + return delta.Seconds() > c.refreshFrequency.Seconds() } // Get has been implemented to read from the cache without further synchronization diff --git a/modules/prebid/rulesengine/cache_test.go b/modules/prebid/rulesengine/cache_test.go index 523eeaee8a..49982d1bec 100644 --- a/modules/prebid/rulesengine/cache_test.go +++ b/modules/prebid/rulesengine/cache_test.go @@ -2,6 +2,7 @@ package rulesengine import ( "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -12,7 +13,7 @@ func TestGet(t *testing.T) { hashedConfig: "hash1", }, } - cache := NewCache() + cache := NewCache(0) cache.m.Store(innerStorage) testCases := []struct { @@ -47,7 +48,7 @@ func TestSet(t *testing.T) { hashedConfig: "hash1", }, } - cache := NewCache() + cache := NewCache(0) cache.m.Store(innerStorage) testCases := []struct { @@ -161,7 +162,7 @@ func TestDelete(t *testing.T) { }, } - cache := NewCache() + cache := NewCache(0) cache.m.Store(originalInnerStorage) for _, tc := range testCases { @@ -174,3 +175,46 @@ func TestDelete(t *testing.T) { }) } } + +func TestExpired(t *testing.T) { + testCases := []struct { + name string + inTimestamp time.Time + refreshRateSeconds int + expectedResult bool + }{ + { + name: "expired", + inTimestamp: mockTimeUtil{}.Now().Add(-6 * time.Second), + refreshRateSeconds: 5, + expectedResult: true, + }, + { + name: "not_expired", + inTimestamp: mockTimeUtil{}.Now().Add(-4 * time.Second), + refreshRateSeconds: 5, + expectedResult: false, + }, + { + name: "no_refresh_rate", + inTimestamp: mockTimeUtil{}.Now().Add(-10 * time.Second), + refreshRateSeconds: 0, + expectedResult: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + c := NewCache(tc.refreshRateSeconds) + c.t = mockTimeUtil{} + res := c.Expired(tc.inTimestamp) + assert.Equal(t, tc.expectedResult, res) + }) + } +} + +type mockTimeUtil struct{} + +func (mt mockTimeUtil) Now() time.Time { + return time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) +} diff --git a/modules/prebid/rulesengine/module.go b/modules/prebid/rulesengine/module.go index c2c26deba3..bfea26d92f 100644 --- a/modules/prebid/rulesengine/module.go +++ b/modules/prebid/rulesengine/module.go @@ -5,20 +5,18 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "time" + + "github.com/buger/jsonparser" hs "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/moduledeps" "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/util/timeutil" ) -const fiveMinutes = time.Duration(300) * time.Second - // Builder configures the rules engine module initiating an in-memory cache and kicking // off a go routine that builds tree structures that represent rule sets optimized for finding // a rule to applies for a given request. -func Builder(_ json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { +func Builder(cfg json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { schemaValidator, err := config.CreateSchemaValidator(config.RulesEngineSchemaFilePath) if err != nil { return nil, err @@ -30,7 +28,13 @@ func Builder(_ json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { schemaValidator: schemaValidator, monitor: &treeManagerLogger{}, } - c := NewCache() + + refreshRate, err := getRefreshRate(cfg) + if err != nil { + return nil, err + } + + c := NewCache(refreshRate) go tm.Run(c) @@ -77,7 +81,7 @@ func (m Module) HandleProcessedAuctionHook( }, nil } // cache hit - if rebuildTrees(co, &miCtx.AccountConfig) { + if rebuildTrees(co, &miCtx.AccountConfig, m.Cache) { bi := buildInstruction{ accountID: miCtx.AccountID, config: &miCtx.AccountConfig, @@ -103,25 +107,14 @@ func (m Module) Shutdown() { <-m.TreeManager.done } -// rebuildTrees returns true if the trees for this account need to be rebuilt; false otherwise -func rebuildTrees(co *cacheEntry, jsonConfig *json.RawMessage) bool { - if !expired(&timeutil.RealTime{}, co.timestamp) { +// rebuildTrees returns true if the trees need to be rebuilt; false otherwise +func rebuildTrees(co *cacheEntry, jsonConfig *json.RawMessage, cacher cacher) bool { + if !cacher.Expired(co.timestamp) { return false } return configChanged(co.hashedConfig, jsonConfig) } -// expired returns true if the refresh time has expired; false otherwise -func expired(t timeutil.Time, ts time.Time) bool { - currentTime := t.Now().UTC() - - delta := currentTime.Sub(ts.UTC()) - if delta.Seconds() > fiveMinutes.Seconds() { - return true - } - return false -} - // configChanged hashes the raw JSON config comparing it with the old hash returning // true with the new hash if the hashes are different and false otherwise func configChanged(oldHash hash, data *json.RawMessage) bool { @@ -136,3 +129,15 @@ func configChanged(oldHash hash, data *json.RawMessage) bool { } return false } + +func getRefreshRate(jsonCfg json.RawMessage) (int, error) { + updateFrequency, err := jsonparser.GetInt(jsonCfg, "refreshrateseconds") + + if err == jsonparser.KeyPathNotFoundError { + return 0, nil + } + if err != nil { + return 0, err + } + return int(updateFrequency), nil +} diff --git a/modules/prebid/rulesengine/module_test.go b/modules/prebid/rulesengine/module_test.go index 1ae135c16b..687d75a076 100644 --- a/modules/prebid/rulesengine/module_test.go +++ b/modules/prebid/rulesengine/module_test.go @@ -5,45 +5,9 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/util/timeutil" "github.com/stretchr/testify/assert" ) -func TestExpired(t *testing.T) { - testCases := []struct { - name string - inTime timeutil.Time - inTimestamp time.Time - expectedResult bool - }{ - { - name: "expired", - inTime: mockTimeUtil{}, - inTimestamp: mockTimeUtil{}.Now().Add(-time.Hour), - expectedResult: true, - }, - { - name: "not_expired", - inTime: mockTimeUtil{}, - inTimestamp: mockTimeUtil{}.Now().Add(time.Hour), - expectedResult: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - res := expired(tc.inTime, tc.inTimestamp) - assert.Equal(t, tc.expectedResult, res) - }) - } -} - -type mockTimeUtil struct{} - -func (mt mockTimeUtil) Now() time.Time { - return time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) -} - var sampleJsonConfig json.RawMessage = json.RawMessage(`{"enabled": true, "ruleSets": []}`) func TestConfigChanged(t *testing.T) { @@ -84,42 +48,117 @@ func TestConfigChanged(t *testing.T) { func TestRebuildTrees(t *testing.T) { testCases := []struct { - name string - inCacheEntry *cacheEntry - inJsonConfig *json.RawMessage - expectedResult bool + name string + inCacheEntry *cacheEntry + inJsonConfig *json.RawMessage + refreshRateSeconds int + expectedResult bool }{ { name: "non_expired_cache_entry_so_no_rebuild", inCacheEntry: &cacheEntry{ - timestamp: time.Date(2050, 1, 1, 0, 0, 0, 0, time.UTC), + timestamp: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), }, - expectedResult: false, + inJsonConfig: &sampleJsonConfig, + refreshRateSeconds: 10, + expectedResult: false, }, { - name: "expired_entry_but_same_config_so_no_rebuild", + name: "expired_entry_but_same_config_and_default_no_update_so_no_rebuild", inCacheEntry: &cacheEntry{ timestamp: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), hashedConfig: "e21c19982a618f9dd3286fc2eb08dad62a1e9ee81d51ffa94b267ab2e3813964", }, - inJsonConfig: &sampleJsonConfig, - expectedResult: false, + inJsonConfig: &sampleJsonConfig, + refreshRateSeconds: 1, + expectedResult: false, }, { - name: "expired_entry_and_different_config_so_rebuild", + name: "expired_entry_but_same_config_and_zero_minutes_update_so_no_rebuild", inCacheEntry: &cacheEntry{ timestamp: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), + hashedConfig: "e21c19982a618f9dd3286fc2eb08dad62a1e9ee81d51ffa94b267ab2e3813964", + }, + inJsonConfig: &sampleJsonConfig, + refreshRateSeconds: 0, + expectedResult: false, + }, + { + name: "expired_entry_and_different_config_so_rebuild", + inCacheEntry: &cacheEntry{ + timestamp: time.Date(1999, 1, 1, 0, 0, 0, 0, time.UTC), hashedConfig: "oldHash", }, - inJsonConfig: &sampleJsonConfig, - expectedResult: true, + inJsonConfig: &sampleJsonConfig, + refreshRateSeconds: 1, + expectedResult: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - res := rebuildTrees(tc.inCacheEntry, tc.inJsonConfig) + refreshFreq := time.Duration(tc.refreshRateSeconds) * time.Second + var c cacher = &cache{ + refreshFrequency: refreshFreq, + t: mockTimeUtil{}, + } + res := rebuildTrees(tc.inCacheEntry, tc.inJsonConfig, c) assert.Equal(t, tc.expectedResult, res) }) } } + +func TestGetRefreshRate(t *testing.T) { + + testCases := []struct { + name string + inData json.RawMessage + expectedRefreshRate int + expectError bool + }{ + { + name: "nil_data", + inData: nil, + expectedRefreshRate: 0, + }, + { + name: "valid_config", + inData: json.RawMessage(`{"enabled": true, "refreshrateseconds": 10}`), + expectedRefreshRate: 10, + }, + { + name: "valid_config_negative_refresh_rate", + inData: json.RawMessage(`{"enabled": true, "refreshrateseconds": -10}`), + expectedRefreshRate: -10, + }, + { + name: "valid_config_no_refresh_rate", + inData: json.RawMessage(`{"enabled": true}`), + expectedRefreshRate: 0, + }, + { + name: "invalid_config", + inData: json.RawMessage(`{"enabled": true, "refreshrateseconds": "test"}`), + expectedRefreshRate: 0, + expectError: true, + }, + { + name: "path_not_foud", + inData: json.RawMessage(`{"enabled": true, "test": 10}`), + expectedRefreshRate: 0, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := getRefreshRate(tc.inData) + if tc.expectError { + assert.Error(t, err, "Expected an error but got none") + } else { + assert.NoError(t, err, "Expected no error but got one") + } + assert.Equal(t, tc.expectedRefreshRate, res) + }) + } +} diff --git a/modules/prebid/rulesengine/tree_manager.go b/modules/prebid/rulesengine/tree_manager.go index 122cf60f90..6e72853f88 100644 --- a/modules/prebid/rulesengine/tree_manager.go +++ b/modules/prebid/rulesengine/tree_manager.go @@ -33,7 +33,7 @@ func (tm *treeManager) Run(c cacher) error { } cacheObj := c.Get(req.accountID) - if cacheObj != nil && !rebuildTrees(cacheObj, req.config) { + if cacheObj != nil && !rebuildTrees(cacheObj, req.config, c) { break } diff --git a/modules/prebid/rulesengine/tree_manager_test.go b/modules/prebid/rulesengine/tree_manager_test.go index fdf8656792..818b21c6dd 100644 --- a/modules/prebid/rulesengine/tree_manager_test.go +++ b/modules/prebid/rulesengine/tree_manager_test.go @@ -19,7 +19,7 @@ func TestTreeManagerShutdown(t *testing.T) { requests: make(chan buildInstruction, 10), monitor: &treeManagerLogger{}, } - cache := NewCache() + cache := NewCache(0) var wg sync.WaitGroup wg.Add(1) @@ -192,7 +192,7 @@ func TestTreeManagerRun(t *testing.T) { monitor: logger, } - cache := NewCache() + cache := NewCache(0) cache.m.Store(tc.inStoredDataInCache) // run From ade6baf1319f21a8aee68fdc9cf411847c8d49f6 Mon Sep 17 00:00:00 2001 From: Leandro Marty <leandro.marty@rocketlab.ai> Date: Tue, 26 Aug 2025 14:59:10 +0200 Subject: [PATCH 067/272] New Adapter: RocketLab (#4383) --- static/bidder-info/rocketlab.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/bidder-info/rocketlab.yaml diff --git a/static/bidder-info/rocketlab.yaml b/static/bidder-info/rocketlab.yaml new file mode 100644 index 0000000000..2efe3fd48c --- /dev/null +++ b/static/bidder-info/rocketlab.yaml @@ -0,0 +1,8 @@ +aliasOf: 'teqblaze' +endpoint: 'https://traffic1.rocketlab.ai/pserver' +maintainer: + email: 'support@rocketlab.ai' +userSync: + redirect: + url: 'https://usync.rocketlab.ai/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}' + userMacro: '[UID]' From c48d94d9b24f883e93a7676d94c5109c36c46911 Mon Sep 17 00:00:00 2001 From: g-coder-baiai <77920802+g-coder-baiai@users.noreply.github.com> Date: Thu, 28 Aug 2025 02:35:49 +0800 Subject: [PATCH 068/272] change zmaticoo.yaml endpoint (#4471) Co-authored-by: Quentin.zuo <quentin.zuo@eclicktech.com.cn> --- static/bidder-info/zmaticoo.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/zmaticoo.yaml b/static/bidder-info/zmaticoo.yaml index ae7d3eb010..643e28444e 100644 --- a/static/bidder-info/zmaticoo.yaml +++ b/static/bidder-info/zmaticoo.yaml @@ -1,4 +1,4 @@ -endpoint: "https://bid.zmaticoo.com/prebid/bid" +endpoint: "https://rtbbid.zmaticoo.com/prebid/bid" maintainer: email: "adam.li@eclicktech.com.cn" capabilities: From 6c86074ac7be709ef93efbeb08ef9580b4bd77e5 Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Thu, 4 Sep 2025 10:55:35 -0400 Subject: [PATCH 069/272] Metrics: Record GVL fetch count (#4500) --- gdpr/gdpr.go | 8 +++--- gdpr/gdpr_test.go | 5 ++-- gdpr/impl.go | 4 ++- gdpr/impl_test.go | 7 ++--- gdpr/vendorlist-fetching.go | 28 +++++++++++--------- gdpr/vendorlist-fetching_test.go | 37 ++++++++++++++++++--------- metrics/config/metrics.go | 9 +++++++ metrics/go_metrics.go | 7 +++++ metrics/go_metrics_test.go | 1 + metrics/metrics.go | 1 + metrics/metrics_mock.go | 4 +++ metrics/prometheus/prometheus.go | 9 +++++++ metrics/prometheus/prometheus_test.go | 8 ++++++ router/router.go | 4 +-- 14 files changed, 97 insertions(+), 35 deletions(-) diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go index 20c5e9306b..26e04e0b95 100644 --- a/gdpr/gdpr.go +++ b/gdpr/gdpr.go @@ -4,6 +4,7 @@ import ( "context" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -34,16 +35,16 @@ type RequestInfo struct { } // NewPermissionsBuilder takes host config data used to configure the builder function it returns -func NewPermissionsBuilder(cfg config.GDPR, gvlVendorIDs map[openrtb_ext.BidderName]uint16, vendorListFetcher VendorListFetcher) PermissionsBuilder { +func NewPermissionsBuilder(cfg config.GDPR, gvlVendorIDs map[openrtb_ext.BidderName]uint16, vendorListFetcher VendorListFetcher, me metrics.MetricsEngine) PermissionsBuilder { return func(tcf2Cfg TCF2ConfigReader, requestInfo RequestInfo) Permissions { purposeEnforcerBuilder := NewPurposeEnforcerBuilder(tcf2Cfg) - return NewPermissions(cfg, tcf2Cfg, gvlVendorIDs, vendorListFetcher, purposeEnforcerBuilder, requestInfo) + return NewPermissions(cfg, tcf2Cfg, gvlVendorIDs, vendorListFetcher, purposeEnforcerBuilder, requestInfo, me) } } // NewPermissions gets a per-request Permissions object that can then be used to check GDPR permissions for a given bidder. -func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[openrtb_ext.BidderName]uint16, fetcher VendorListFetcher, purposeEnforcerBuilder PurposeEnforcerBuilder, requestInfo RequestInfo) Permissions { +func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[openrtb_ext.BidderName]uint16, fetcher VendorListFetcher, purposeEnforcerBuilder PurposeEnforcerBuilder, requestInfo RequestInfo, metricsEngine metrics.MetricsEngine) Permissions { if !cfg.Enabled { return &AlwaysAllow{} } @@ -60,6 +61,7 @@ func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[ consent: requestInfo.Consent, aliasGVLIDs: requestInfo.AliasGVLIDs, purposeEnforcerBuilder: purposeEnforcerBuilder, + metrics: metricsEngine, } if cfg.HostVendorID == 0 { diff --git a/gdpr/gdpr_test.go b/gdpr/gdpr_test.go index db81d1396a..6329dad858 100644 --- a/gdpr/gdpr_test.go +++ b/gdpr/gdpr_test.go @@ -7,6 +7,7 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" @@ -43,14 +44,14 @@ func TestNewPermissions(t *testing.T) { HostVendorID: tt.hostVendorID, } vendorIDs := map[openrtb_ext.BidderName]uint16{} - vendorListFetcher := func(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { + vendorListFetcher := func(ctx context.Context, specVersion, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) { return nil, nil } fakePurposeEnforcerBuilder := fakePurposeEnforcerBuilder{ purposeEnforcer: nil, }.Builder - perms := NewPermissions(config, &tcf2Config{}, vendorIDs, vendorListFetcher, fakePurposeEnforcerBuilder, RequestInfo{}) + perms := NewPermissions(config, &tcf2Config{}, vendorIDs, vendorListFetcher, fakePurposeEnforcerBuilder, RequestInfo{}, &metrics.MetricsEngineMock{}) assert.IsType(t, tt.wantType, perms, tt.description) } diff --git a/gdpr/impl.go b/gdpr/impl.go index 47fd4521c1..24c5b3010e 100644 --- a/gdpr/impl.go +++ b/gdpr/impl.go @@ -6,6 +6,7 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/consentconstants" tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -19,6 +20,7 @@ type permissionsImpl struct { fetchVendorList VendorListFetcher gdprDefaultValue string hostVendorID int + metrics metrics.MetricsEngine nonStandardPublishers map[string]struct{} purposeEnforcerBuilder PurposeEnforcerBuilder vendorIDs map[openrtb_ext.BidderName]uint16 @@ -199,7 +201,7 @@ func (p *permissionsImpl) allowID(bidder openrtb_ext.BidderName, consentMeta tcf // getVendor retrieves the GVL vendor information for a particular bidder func (p *permissionsImpl) getVendor(ctx context.Context, vendorID uint16, pc parsedConsent) (api.Vendor, error) { - vendorList, err := p.fetchVendorList(ctx, pc.specVersion, pc.listVersion) + vendorList, err := p.fetchVendorList(ctx, pc.specVersion, pc.listVersion, p.metrics) if err != nil { return nil, err } diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go index 79d43d5823..60a688fcc4 100644 --- a/gdpr/impl_test.go +++ b/gdpr/impl_test.go @@ -10,6 +10,7 @@ import ( "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" @@ -883,8 +884,8 @@ func parseVendorListDataV2(t *testing.T, data string) vendorlist.VendorList { return parsed } -func listFetcher(specVersionLists map[uint16]map[uint16]vendorlist.VendorList) func(context.Context, uint16, uint16) (vendorlist.VendorList, error) { - return func(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { +func listFetcher(specVersionLists map[uint16]map[uint16]vendorlist.VendorList) func(context.Context, uint16, uint16, metrics.MetricsEngine) (vendorlist.VendorList, error) { + return func(ctx context.Context, specVersion, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) { if lists, ok := specVersionLists[specVersion]; ok { if data, ok := lists[listVersion]; ok { return data, nil @@ -894,7 +895,7 @@ func listFetcher(specVersionLists map[uint16]map[uint16]vendorlist.VendorList) f } } -func failedListFetcher(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { +func failedListFetcher(ctx context.Context, specVersion, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) { return nil, errors.New("vendor list can't be fetched") } diff --git a/gdpr/vendorlist-fetching.go b/gdpr/vendorlist-fetching.go index dc03548347..c7b462a259 100644 --- a/gdpr/vendorlist-fetching.go +++ b/gdpr/vendorlist-fetching.go @@ -15,11 +15,12 @@ import ( "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "golang.org/x/net/context/ctxhttp" ) type saveVendors func(uint16, uint16, api.VendorList) -type VendorListFetcher func(ctx context.Context, specVersion uint16, listVersion uint16) (vendorlist.VendorList, error) +type VendorListFetcher func(ctx context.Context, specVersion uint16, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) // This file provides the vendorlist-fetching function for Prebid Server. // @@ -27,15 +28,15 @@ type VendorListFetcher func(ctx context.Context, specVersion uint16, listVersion // // Nothing in this file is exported. Public APIs can be found in gdpr.go -func NewVendorListFetcher(initCtx context.Context, cfg config.GDPR, client *http.Client, urlMaker func(uint16, uint16) string) VendorListFetcher { +func NewVendorListFetcher(initCtx context.Context, cfg config.GDPR, client *http.Client, metricsEngine metrics.MetricsEngine, urlMaker func(uint16, uint16) string) VendorListFetcher { cacheSave, cacheLoad := newVendorListCache() preloadContext, cancel := context.WithTimeout(initCtx, cfg.Timeouts.InitTimeout()) defer cancel() - preloadCache(preloadContext, client, urlMaker, cacheSave) + preloadCache(preloadContext, client, urlMaker, cacheSave, metricsEngine) saveOneRateLimited := newOccasionalSaver(cfg.Timeouts.ActiveTimeout()) - return func(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { + return func(ctx context.Context, specVersion, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) { // Attempt To Load From Cache if list := cacheLoad(specVersion, listVersion); list != nil { return list, nil @@ -43,7 +44,7 @@ func NewVendorListFetcher(initCtx context.Context, cfg config.GDPR, client *http // Attempt To Download // - May not add to cache immediately. - saveOneRateLimited(ctx, client, urlMaker(specVersion, listVersion), cacheSave) + saveOneRateLimited(ctx, client, urlMaker(specVersion, listVersion), cacheSave, metricsEngine) // Attempt To Load From Cache Again // - May have been added by the call to saveOneRateLimited. @@ -61,7 +62,7 @@ func makeVendorListNotFoundError(specVersion, listVersion uint16) error { } // preloadCache saves all the known versions of the vendor list for future use. -func preloadCache(ctx context.Context, client *http.Client, urlMaker func(uint16, uint16) string, saver saveVendors) { +func preloadCache(ctx context.Context, client *http.Client, urlMaker func(uint16, uint16) string, saver saveVendors, metricsEngine metrics.MetricsEngine) { versions := [2]struct { specVersion uint16 firstListVersion uint16 @@ -76,10 +77,10 @@ func preloadCache(ctx context.Context, client *http.Client, urlMaker func(uint16 }, } for _, v := range versions { - latestVersion := saveOne(ctx, client, urlMaker(v.specVersion, 0), saver) + latestVersion := saveOne(ctx, client, urlMaker(v.specVersion, 0), saver, metricsEngine) for i := v.firstListVersion; i < latestVersion; i++ { - saveOne(ctx, client, urlMaker(v.specVersion, i), saver) + saveOne(ctx, client, urlMaker(v.specVersion, i), saver, metricsEngine) } } } @@ -98,24 +99,24 @@ func VendorListURLMaker(specVersion, listVersion uint16) string { // The goal here is to update quickly when new versions of the VendorList are released, but not wreck // server performance if a bad CMP starts sending us malformed consent strings that advertize a version // that doesn't exist yet. -func newOccasionalSaver(timeout time.Duration) func(ctx context.Context, client *http.Client, url string, saver saveVendors) { +func newOccasionalSaver(timeout time.Duration) func(ctx context.Context, client *http.Client, url string, saver saveVendors, metricsEngine metrics.MetricsEngine) { lastSaved := &atomic.Value{} lastSaved.Store(time.Time{}) - return func(ctx context.Context, client *http.Client, url string, saver saveVendors) { + return func(ctx context.Context, client *http.Client, url string, saver saveVendors, metricsEngine metrics.MetricsEngine) { now := time.Now() timeSinceLastSave := now.Sub(lastSaved.Load().(time.Time)) if timeSinceLastSave.Minutes() > 10 { withTimeout, cancel := context.WithTimeout(ctx, timeout) defer cancel() - saveOne(withTimeout, client, url, saver) + saveOne(withTimeout, client, url, saver, metricsEngine) lastSaved.Store(now) } } } -func saveOne(ctx context.Context, client *http.Client, url string, saver saveVendors) uint16 { +func saveOne(ctx context.Context, client *http.Client, url string, saver saveVendors, me metrics.MetricsEngine) uint16 { req, err := http.NewRequest("GET", url, nil) if err != nil { glog.Errorf("Failed to build GET %s request. Cookie syncs may be affected: %v", url, err) @@ -136,8 +137,11 @@ func saveOne(ctx context.Context, client *http.Client, url string, saver saveVen } if resp.StatusCode != http.StatusOK { glog.Errorf("GET %s returned %d. Cookie syncs may be affected.", url, resp.StatusCode) + me.RecordGvlListRequest() return 0 } + me.RecordGvlListRequest() + var newList api.VendorList newList, err = vendorlist2.ParseEagerly(respBody) if err != nil { diff --git a/gdpr/vendorlist-fetching_test.go b/gdpr/vendorlist-fetching_test.go index 4e9e31dd93..4ba228244b 100644 --- a/gdpr/vendorlist-fetching_test.go +++ b/gdpr/vendorlist-fetching_test.go @@ -12,6 +12,7 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -95,15 +96,17 @@ func TestFetcherThrottling(t *testing.T) { }))) defer server.Close() - fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), testURLMaker(server)) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(3) + fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), m, testURLMaker(server)) // Dynamically Load List 2 Successfully - _, errList1 := fetcher(context.Background(), 3, 2) + _, errList1 := fetcher(context.Background(), 3, 2, m) assert.NoError(t, errList1) // Fail To Load List 3 Due To Rate Limiting // - The request is rate limited after dynamically list 2. - _, errList2 := fetcher(context.Background(), 3, 3) + _, errList2 := fetcher(context.Background(), 3, 3, m) assert.EqualError(t, errList2, "gdpr vendor list spec version 3 list version 3 does not exist, or has not been loaded yet. Try again in a few minutes") } @@ -118,8 +121,10 @@ func TestMalformedVendorlist(t *testing.T) { }))) defer server.Close() - fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), testURLMaker(server)) - _, err := fetcher(context.Background(), 3, 1) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(3) + fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), m, testURLMaker(server)) + _, err := fetcher(context.Background(), 3, 1, m) // Fetching should fail since vendor list could not be unmarshalled. assert.Error(t, err) @@ -131,8 +136,10 @@ func TestServerUrlInvalid(t *testing.T) { invalidURLGenerator := func(uint16, uint16) string { return " http://invalid-url-has-leading-whitespace" } - fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), invalidURLGenerator) - _, err := fetcher(context.Background(), 3, 1) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(2) + fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), m, invalidURLGenerator) + _, err := fetcher(context.Background(), 3, 1, m) assert.EqualError(t, err, "gdpr vendor list spec version 3 list version 1 does not exist, or has not been loaded yet. Try again in a few minutes") } @@ -141,8 +148,10 @@ func TestServerUnavailable(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) server.Close() - fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), testURLMaker(server)) - _, err := fetcher(context.Background(), 3, 1) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(2) + fetcher := NewVendorListFetcher(context.Background(), testConfig(), server.Client(), m, testURLMaker(server)) + _, err := fetcher(context.Background(), 3, 1, m) assert.EqualError(t, err, "gdpr vendor list spec version 3 list version 1 does not exist, or has not been loaded yet. Try again in a few minutes") } @@ -253,7 +262,9 @@ func TestPreloadCache(t *testing.T) { defer server.Close() s := make(saver, 0, 5) - preloadCache(context.Background(), server.Client(), testURLMaker(server), s.saveVendorLists) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(5) + preloadCache(context.Background(), server.Client(), testURLMaker(server), s.saveVendorLists, m) expectedLoadedVersions := []versionInfo{ {specVersion: 2, listVersion: 2}, @@ -380,8 +391,10 @@ type testExpected struct { func runTest(t *testing.T, test test, server *httptest.Server) { config := testConfig() - fetcher := NewVendorListFetcher(context.Background(), config, server.Client(), testURLMaker(server)) - vendorList, err := fetcher(context.Background(), test.setup.specVersion, test.setup.listVersion) + m := &metrics.MetricsEngineMock{} + m.On("RecordGvlListRequest").Times(3) + fetcher := NewVendorListFetcher(context.Background(), config, server.Client(), m, testURLMaker(server)) + vendorList, err := fetcher(context.Background(), test.setup.specVersion, test.setup.listVersion, m) if test.expected.errorMessage != "" { assert.EqualError(t, err, test.expected.errorMessage, test.description+":error") diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index 563f632e1a..1a378e0faf 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -293,6 +293,12 @@ func (me *MultiMetricsEngine) RecordStoredResponse(pubId string) { } } +func (me *MultiMetricsEngine) RecordGvlListRequest() { + for _, thisME := range *me { + thisME.RecordGvlListRequest() + } +} + func (me *MultiMetricsEngine) RecordAdsCertReq(success bool) { for _, thisME := range *me { thisME.RecordAdsCertReq(success) @@ -513,6 +519,9 @@ func (me *NilMetricsEngine) RecordDebugRequest(debugEnabled bool, pubId string) func (me *NilMetricsEngine) RecordStoredResponse(pubId string) { } +func (me *NilMetricsEngine) RecordGvlListRequest() { +} + func (me *NilMetricsEngine) RecordAdsCertReq(success bool) { } diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index 4e015fa282..3f40b87f99 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -35,6 +35,7 @@ type Metrics struct { TLSHandshakeTimer metrics.Timer BidderServerResponseTimer metrics.Timer StoredResponsesMeter metrics.Meter + GvlListRequestsMeter metrics.Meter // Metrics for OpenRTB requests specifically RequestStatuses map[RequestType]map[RequestStatus]metrics.Meter @@ -182,6 +183,7 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr SetUidStatusMeter: make(map[SetUidStatus]metrics.Meter), SyncerSetsMeter: make(map[string]map[SyncerSetUidStatus]metrics.Meter), StoredResponsesMeter: blankMeter, + GvlListRequestsMeter: blankMeter, ImpsTypeBanner: blankMeter, ImpsTypeVideo: blankMeter, @@ -301,6 +303,7 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d newMetrics.PrebidCacheRequestTimerSuccess = metrics.GetOrRegisterTimer("prebid_cache_request_time.ok", registry) newMetrics.PrebidCacheRequestTimerError = metrics.GetOrRegisterTimer("prebid_cache_request_time.err", registry) newMetrics.StoredResponsesMeter = metrics.GetOrRegisterMeter("stored_responses", registry) + newMetrics.GvlListRequestsMeter = metrics.GetOrRegisterMeter("gvl_requests", registry) newMetrics.OverheadTimer = makeOverheadTimerMetrics(registry) newMetrics.BidderServerResponseTimer = metrics.GetOrRegisterTimer("bidder_server_response_time_seconds", registry) @@ -627,6 +630,10 @@ func (me *Metrics) RecordStoredResponse(pubId string) { } } +func (me *Metrics) RecordGvlListRequest() { + me.GvlListRequestsMeter.Mark(1) +} + func (me *Metrics) RecordImps(labels ImpLabels) { me.ImpMeter.Mark(int64(1)) if labels.BannerImps { diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index 9b7f7302bf..559abd3e25 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -36,6 +36,7 @@ func TestNewMetrics(t *testing.T) { ensureContains(t, registry, "setuid_requests.gdpr_blocked_host_cookie", m.SetUidStatusMeter[SetUidGDPRHostCookieBlocked]) ensureContains(t, registry, "setuid_requests.syncer_unknown", m.SetUidStatusMeter[SetUidSyncerUnknown]) ensureContains(t, registry, "stored_responses", m.StoredResponsesMeter) + ensureContains(t, registry, "gvl_requests", m.GvlListRequestsMeter) ensureContains(t, registry, "prebid_cache_request_time.ok", m.PrebidCacheRequestTimerSuccess) ensureContains(t, registry, "prebid_cache_request_time.err", m.PrebidCacheRequestTimerError) diff --git a/metrics/metrics.go b/metrics/metrics.go index 54fb355688..e9c71712a1 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -459,6 +459,7 @@ type MetricsEngine interface { RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.BidderName) RecordDebugRequest(debugEnabled bool, pubId string) RecordStoredResponse(pubId string) + RecordGvlListRequest() RecordAdsCertReq(success bool) RecordAdsCertSignTime(adsCertSignTime time.Duration) RecordBidValidationCreativeSizeError(adapter openrtb_ext.BidderName, account string) diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index d305113da8..911bcaf4b6 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -175,6 +175,10 @@ func (me *MetricsEngineMock) RecordStoredResponse(pubId string) { me.Called(pubId) } +func (me *MetricsEngineMock) RecordGvlListRequest() { + me.Called() +} + func (me *MetricsEngineMock) RecordAdsCertReq(success bool) { me.Called(success) } diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 3c8adfcc9c..8da9e49a35 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -53,6 +53,7 @@ type Metrics struct { privacyLMT *prometheus.CounterVec privacyTCF *prometheus.CounterVec storedResponses prometheus.Counter + gvlListRequests prometheus.Counter storedResponsesFetchTimer *prometheus.HistogramVec storedResponsesErrors *prometheus.CounterVec adsCertRequests *prometheus.CounterVec @@ -364,6 +365,10 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "stored_responses", "Count of total requests to Prebid Server that have stored responses") + metrics.gvlListRequests = newCounterWithoutLabels(cfg, reg, + "gvl_requests", + "Count number of times GVL list is fetched") + metrics.adapterBids = newCounter(cfg, reg, "adapter_bids", "Count of bids labeled by adapter and markup delivery type (adm or nurl).", @@ -700,6 +705,10 @@ func (m *Metrics) RecordStoredResponse(pubId string) { } } +func (m *Metrics) RecordGvlListRequest() { + m.gvlListRequests.Inc() +} + func (m *Metrics) RecordImps(labels metrics.ImpLabels) { m.impressions.With(prometheus.Labels{ isBannerLabel: strconv.FormatBool(labels.BannerImps), diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index 3ec5969bb6..a22bb8385f 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -1895,6 +1895,14 @@ func TestStoredResponsesMetric(t *testing.T) { } } +func TestRecordGvlListRequest(t *testing.T) { + m := createMetricsForTesting() + + m.RecordGvlListRequest() + + assertCounterValue(t, "Record instance of fetched GVL list", "success", m.gvlListRequests, 1.00) +} + func TestRecordAdsCertReqMetric(t *testing.T) { testCases := []struct { description string diff --git a/router/router.go b/router/router.go index 05d0d99233..9eeadaa802 100644 --- a/router/router.go +++ b/router/router.go @@ -211,8 +211,8 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R defReqJSON := readDefaultRequest(cfg.DefReqConfig) gvlVendorIDs := cfg.BidderInfos.ToGVLVendorIDMap() - vendorListFetcher := gdpr.NewVendorListFetcher(context.Background(), cfg.GDPR, generalHttpClient, gdpr.VendorListURLMaker) - gdprPermsBuilder := gdpr.NewPermissionsBuilder(cfg.GDPR, gvlVendorIDs, vendorListFetcher) + vendorListFetcher := gdpr.NewVendorListFetcher(context.Background(), cfg.GDPR, generalHttpClient, r.MetricsEngine, gdpr.VendorListURLMaker) + gdprPermsBuilder := gdpr.NewPermissionsBuilder(cfg.GDPR, gvlVendorIDs, vendorListFetcher, r.MetricsEngine) tcf2CfgBuilder := gdpr.NewTCF2Config cacheClient := pbc.NewClient(cacheHttpClient, &cfg.CacheURL, &cfg.ExtCacheURL, r.MetricsEngine) From 58945563e35c76d3ee1b9a8f2664e9ab73e1ecbc Mon Sep 17 00:00:00 2001 From: andre-gielow-ttd <124626380+andre-gielow-ttd@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:09:19 -0400 Subject: [PATCH 070/272] TheTradeDesk: Resolve burl if not resolved (#4481) --- adapters/thetradedesk/thetradedesk.go | 5 ++-- adapters/thetradedesk/thetradedesk_test.go | 28 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go index f22744ffdc..f3d81d2a06 100644 --- a/adapters/thetradedesk/thetradedesk.go +++ b/adapters/thetradedesk/thetradedesk.go @@ -241,6 +241,7 @@ func resolveAuctionPriceMacros(bid *openrtb2.Bid) { return } price := strconv.FormatFloat(bid.Price, 'f', -1, 64) - bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1) - bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) + bid.NURL = strings.ReplaceAll(bid.NURL, "${AUCTION_PRICE}", price) + bid.AdM = strings.ReplaceAll(bid.AdM, "${AUCTION_PRICE}", price) + bid.BURL = strings.ReplaceAll(bid.BURL, "${AUCTION_PRICE}", price) } diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go index 11ffda30d9..dec4652ce7 100644 --- a/adapters/thetradedesk/thetradedesk_test.go +++ b/adapters/thetradedesk/thetradedesk_test.go @@ -458,6 +458,7 @@ func TestResolveAuctionPriceMacros(t *testing.T) { bid *openrtb2.Bid expectedNURL string expectedAdM string + expectedBURL string }{ { name: "nil_bid", @@ -469,9 +470,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 1.23, NURL: "http://example.com/nurl", AdM: "<div>Ad content</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=1.23¶m2=abc", }, expectedNURL: "http://example.com/nurl", expectedAdM: "<div>Ad content</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=1.23¶m2=abc", }, { name: "macros_in_both_nurl_and_adm", @@ -479,9 +482,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 1.50, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", AdM: "<div>Ad content with price ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=1.5", expectedAdM: "<div>Ad content with price 1.5</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=1.5¶m2=abc", }, { name: "macro_only_in_nurl", @@ -503,15 +508,25 @@ func TestResolveAuctionPriceMacros(t *testing.T) { expectedNURL: "http://example.com/nurl", expectedAdM: "<div>Price: 0.99</div>", }, + { + name: "macro_only_in_burl", + bid: &openrtb2.Bid{ + Price: 0.99, + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", + }, + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=0.99¶m2=abc", + }, { name: "multiple_macros_in_same_field", bid: &openrtb2.Bid{ Price: 3.14, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}&backup_price=${AUCTION_PRICE}", AdM: "<div>Price: ${AUCTION_PRICE}, Backup: ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=${AUCTION_PRICE}", }, expectedNURL: "http://example.com/nurl?price=3.14&backup_price=3.14", expectedAdM: "<div>Price: 3.14, Backup: 3.14</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=3.14¶m2=3.14", }, { name: "zero_price", @@ -519,9 +534,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 0.0, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", AdM: "<div>Price: ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=0", expectedAdM: "<div>Price: 0</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=0¶m2=abc", }, { name: "very_small_price", @@ -529,9 +546,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 0.001, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", AdM: "<div>Price: ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=0.001", expectedAdM: "<div>Price: 0.001</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=0.001¶m2=abc", }, { name: "large_price", @@ -539,9 +558,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 999.999, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", AdM: "<div>Price: ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=999.999", expectedAdM: "<div>Price: 999.999</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=999.999¶m2=abc", }, { name: "integer_price", @@ -549,9 +570,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 5.0, NURL: "http://example.com/nurl?price=${AUCTION_PRICE}", AdM: "<div>Price: ${AUCTION_PRICE}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${AUCTION_PRICE}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=5", expectedAdM: "<div>Price: 5</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=5¶m2=abc", }, { name: "empty_nurl_and_adm", @@ -559,9 +582,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 1.23, NURL: "", AdM: "", + BURL: "", }, expectedNURL: "", expectedAdM: "", + expectedBURL: "", }, { name: "case_sensitive_macro_not_replaced", @@ -569,9 +594,11 @@ func TestResolveAuctionPriceMacros(t *testing.T) { Price: 1.50, NURL: "http://example.com/nurl?price=${auction_price}", AdM: "<div>Price: ${Auction_Price}</div>", + BURL: "http://adsrvr.org/feedback/xxxx?wp=${Auction_Price}¶m2=abc", }, expectedNURL: "http://example.com/nurl?price=${auction_price}", expectedAdM: "<div>Price: ${Auction_Price}</div>", + expectedBURL: "http://adsrvr.org/feedback/xxxx?wp=${Auction_Price}¶m2=abc", }, } @@ -592,6 +619,7 @@ func TestResolveAuctionPriceMacros(t *testing.T) { assert.Equal(t, tt.expectedNURL, testBid.NURL, "NURL should match expected value") assert.Equal(t, tt.expectedAdM, testBid.AdM, "AdM should match expected value") + assert.Equal(t, tt.expectedBURL, testBid.BURL, "BRUL should match expected value") }) } } From 689c5c8dd46ebbdaa6c1dc42e15199b5c3a00afc Mon Sep 17 00:00:00 2001 From: prebidPinkLion <prebid@pinklion.io> Date: Thu, 4 Sep 2025 20:06:07 +0300 Subject: [PATCH 071/272] New Adapter: pinkLion (#4376) --- static/bidder-info/pinkLion.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/pinkLion.yaml diff --git a/static/bidder-info/pinkLion.yaml b/static/bidder-info/pinkLion.yaml new file mode 100644 index 0000000000..52e9e0f1ba --- /dev/null +++ b/static/bidder-info/pinkLion.yaml @@ -0,0 +1,4 @@ +aliasOf: "teqblaze" +endpoint: "https://us-east-ep.pinklion.io/pserver" +maintainer: + email: "prebid@pinklion.io" \ No newline at end of file From 01daa2cfa0525ede6f08db0daa271e5adf4402ee Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Thu, 4 Sep 2025 15:11:49 -0400 Subject: [PATCH 072/272] Metrics: Record HTTP connections wanted and obtained (#4518) --- exchange/bidder.go | 2 ++ exchange/bidder_test.go | 2 ++ metrics/config/metrics.go | 18 ++++++++++++++++++ metrics/go_metrics.go | 14 ++++++++++++++ metrics/go_metrics_test.go | 2 ++ metrics/metrics.go | 2 ++ metrics/metrics_mock.go | 8 ++++++++ metrics/prometheus/prometheus.go | 18 ++++++++++++++++++ metrics/prometheus/prometheus_test.go | 20 ++++++++++++++++++++ 9 files changed, 86 insertions(+) diff --git a/exchange/bidder.go b/exchange/bidder.go index a305a0e84b..c0c748b9b5 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -735,6 +735,7 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context // GetConn is called before a connection is created or retrieved from an idle pool GetConn: func(hostPort string) { connStart = time.Now() + bidder.me.RecordConnectionWant() }, // GotConn is called after a successful connection is obtained GotConn: func(info httptrace.GotConnInfo) { @@ -752,6 +753,7 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context } bidder.me.RecordAdapterConnections(bidder.BidderName, info.Reused, connWaitTime) + bidder.me.RecordConnectionGot() }, // DNSStart is called when a DNS lookup begins. DNSStart: func(info httptrace.DNSStartInfo) { diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index 50e919c2a6..e8e0b5a8b9 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -2085,6 +2085,8 @@ func TestCallRecordAdapterConnections(t *testing.T) { mockMetricEngine.On("RecordAdapterConnections", expectedAdapterName, false, mock.MatchedBy(compareConnWaitTime)).Once() mockMetricEngine.On("RecordOverheadTime", metrics.PreBidder, mock.Anything).Once() mockMetricEngine.On("RecordBidderServerResponseTime", mock.Anything).Once() + mockMetricEngine.On("RecordConnectionWant").Once() + mockMetricEngine.On("RecordConnectionGot").Once() // Run requestBid using an http.Client with a mock handler bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, mockMetricEngine, openrtb_ext.BidderAppnexus, nil, "") diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index 1a378e0faf..4256e8125c 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -384,6 +384,18 @@ func (me *MultiMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderN } } +func (me *MultiMetricsEngine) RecordConnectionWant() { + for _, thisME := range *me { + thisME.RecordConnectionWant() + } +} + +func (me *MultiMetricsEngine) RecordConnectionGot() { + for _, thisME := range *me { + thisME.RecordConnectionGot() + } +} + // NilMetricsEngine implements the MetricsEngine interface where no metrics are actually captured. This is // used if no metric backend is configured and also for tests. type NilMetricsEngine struct{} @@ -566,3 +578,9 @@ func (me *NilMetricsEngine) RecordModuleTimeout(labels metrics.ModuleLabels) { // RecordAdapterThrottled as a noop func (me *NilMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderName) { } + +func (me *NilMetricsEngine) RecordConnectionWant() { +} + +func (me *NilMetricsEngine) RecordConnectionGot() { +} diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index 3f40b87f99..aa98b18415 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -18,6 +18,8 @@ type Metrics struct { TMaxTimeoutCounter metrics.Counter ConnectionAcceptErrorMeter metrics.Meter ConnectionCloseErrorMeter metrics.Meter + ConnectionWantCounter metrics.Counter + ConnectionGotCounter metrics.Counter ImpMeter metrics.Meter AppRequestMeter metrics.Meter NoCookieMeter metrics.Meter @@ -160,6 +162,8 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr ConnectionCounter: metrics.NilCounter{}, ConnectionAcceptErrorMeter: blankMeter, ConnectionCloseErrorMeter: blankMeter, + ConnectionWantCounter: metrics.NilCounter{}, + ConnectionGotCounter: metrics.NilCounter{}, ImpMeter: blankMeter, AppRequestMeter: blankMeter, DebugRequestMeter: blankMeter, @@ -287,6 +291,8 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d newMetrics.TMaxTimeoutCounter = metrics.GetOrRegisterCounter("tmax_timeout", registry) newMetrics.ConnectionAcceptErrorMeter = metrics.GetOrRegisterMeter("connection_accept_errors", registry) newMetrics.ConnectionCloseErrorMeter = metrics.GetOrRegisterMeter("connection_close_errors", registry) + newMetrics.ConnectionWantCounter = metrics.GetOrRegisterCounter("connection_want", registry) + newMetrics.ConnectionGotCounter = metrics.GetOrRegisterCounter("connection_got", registry) newMetrics.ImpMeter = metrics.GetOrRegisterMeter("imps_requested", registry) newMetrics.ImpsTypeBanner = metrics.GetOrRegisterMeter("imp_banner", registry) @@ -670,6 +676,14 @@ func (me *Metrics) RecordConnectionClose(success bool) { } } +func (me *Metrics) RecordConnectionWant() { + me.ConnectionWantCounter.Inc(1) +} + +func (me *Metrics) RecordConnectionGot() { + me.ConnectionGotCounter.Inc(1) +} + // RecordRequestTime implements a part of the MetricsEngine interface. The calling code is responsible // for determining the call duration. func (me *Metrics) RecordRequestTime(labels Labels, length time.Duration) { diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index 559abd3e25..a5283a35c2 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -86,6 +86,8 @@ func TestNewMetrics(t *testing.T) { ensureContains(t, registry, "request_over_head_time.make-bidder-requests", m.OverheadTimer[MakeBidderRequests]) ensureContains(t, registry, "bidder_server_response_time_seconds", m.BidderServerResponseTimer) ensureContains(t, registry, "tmax_timeout", m.TMaxTimeoutCounter) + ensureContains(t, registry, "connection_want", m.ConnectionWantCounter) + ensureContains(t, registry, "connection_got", m.ConnectionGotCounter) for module, stages := range moduleStageNames { for _, stage := range stages { diff --git a/metrics/metrics.go b/metrics/metrics.go index e9c71712a1..71c02a7557 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -474,4 +474,6 @@ type MetricsEngine interface { RecordModuleExecutionError(labels ModuleLabels) RecordModuleTimeout(labels ModuleLabels) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) + RecordConnectionWant() + RecordConnectionGot() } diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index 911bcaf4b6..f33bd7bf99 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -234,3 +234,11 @@ func (me *MetricsEngineMock) RecordModuleTimeout(labels ModuleLabels) { func (me *MetricsEngineMock) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { me.Called(adapterName) } + +func (me *MetricsEngineMock) RecordConnectionWant() { + me.Called() +} + +func (me *MetricsEngineMock) RecordConnectionGot() { + me.Called() +} diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 8da9e49a35..a2cc60f768 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -23,6 +23,8 @@ type Metrics struct { connectionsClosed prometheus.Counter connectionsError *prometheus.CounterVec connectionsOpened prometheus.Counter + connectionWant prometheus.Counter + connectionGot prometheus.Counter cookieSync *prometheus.CounterVec setUid *prometheus.CounterVec impressions *prometheus.CounterVec @@ -187,6 +189,14 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "connections_opened", "Count of successful connections opened to Prebid Server.") + metrics.connectionWant = newCounterWithoutLabels(cfg, reg, + "connections_want", + "Count number of times client trace calls GetConn.") + + metrics.connectionGot = newCounterWithoutLabels(cfg, reg, + "connections_got", + "Count number of times client trace calls GotConn.") + metrics.tmaxTimeout = newCounterWithoutLabels(cfg, reg, "tmax_timeout", "Count of requests rejected due to Tmax timeout exceed.") @@ -1110,3 +1120,11 @@ func (m *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { adapterLabel: strings.ToLower(string(adapterName)), }).Inc() } + +func (m *Metrics) RecordConnectionWant() { + m.connectionWant.Inc() +} + +func (m *Metrics) RecordConnectionGot() { + m.connectionGot.Inc() +} diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index a22bb8385f..7ab1fb6502 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -75,6 +75,8 @@ func TestConnectionMetrics(t *testing.T) { expectedOpenedErrorCount float64 expectedClosedCount float64 expectedClosedErrorCount float64 + expectedConnectionWant float64 + expectedConnectionGot float64 }{ { description: "Open Success", @@ -116,6 +118,20 @@ func TestConnectionMetrics(t *testing.T) { expectedClosedCount: 0, expectedClosedErrorCount: 1, }, + { + description: "connection-want", + testCase: func(m *Metrics) { + m.RecordConnectionWant() + }, + expectedConnectionWant: 1, + }, + { + description: "connection-got", + testCase: func(m *Metrics) { + m.RecordConnectionGot() + }, + expectedConnectionGot: 1, + }, } for _, test := range testCases { @@ -135,6 +151,10 @@ func TestConnectionMetrics(t *testing.T) { test.expectedClosedErrorCount, prometheus.Labels{ connectionErrorLabel: connectionCloseError, }) + assertCounterValue(t, test.description, "connectionWant", m.connectionWant, + test.expectedConnectionWant) + assertCounterValue(t, test.description, "connectionGot", m.connectionGot, + test.expectedConnectionGot) } } From f63f77ae870c1010ad5076d9225ddbf8c32322a4 Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Thu, 4 Sep 2025 17:01:22 -0400 Subject: [PATCH 073/272] Metrics: Record incoming request sizes (#4495) --- endpoints/openrtb2/amp_auction.go | 9 ++--- endpoints/openrtb2/auction.go | 1 + endpoints/openrtb2/video_auction.go | 1 + metrics/config/metrics_test.go | 4 +++ metrics/go_metrics.go | 17 ++++++++++ metrics/go_metrics_test.go | 2 ++ metrics/metrics.go | 37 ++++++++++++++++++++ metrics/metrics_test.go | 49 +++++++++++++++++++++++++++ metrics/prometheus/prometheus.go | 15 ++++++++ metrics/prometheus/prometheus_test.go | 4 +++ 10 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 metrics/metrics_test.go diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 631041eee3..9d5bc24896 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -160,7 +160,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h // There is no body for AMP requests, so we pass a nil body and ignore the return value. _, rejectErr := hookExecutor.ExecuteEntrypointStage(r, nilBody) - reqWrapper, storedAuctionResponses, storedBidResponses, bidderImpReplaceImp, errL := deps.parseAmpRequest(r) + reqWrapper, storedAuctionResponses, storedBidResponses, bidderImpReplaceImp, errL := deps.parseAmpRequest(r, labels) ao.Errors = append(ao.Errors, errL...) // Process reject after parsing amp request, so we can use reqWrapper. // There is no body for AMP requests, so we pass a nil body and ignore the return value. @@ -503,9 +503,9 @@ func getExtBidResponse( // possible, it will return errors with messages that suggest improvements. // // If the errors list has at least one element, then no guarantees are made about the returned request. -func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openrtb_ext.RequestWrapper, storedAuctionResponses stored_responses.ImpsWithBidResponses, storedBidResponses stored_responses.ImpBidderStoredResp, bidderImpReplaceImp stored_responses.BidderImpReplaceImpID, errs []error) { +func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request, labels metrics.Labels) (req *openrtb_ext.RequestWrapper, storedAuctionResponses stored_responses.ImpsWithBidResponses, storedBidResponses stored_responses.ImpBidderStoredResp, bidderImpReplaceImp stored_responses.BidderImpReplaceImpID, errs []error) { // Load the stored request for the AMP ID. - reqNormal, storedAuctionResponses, storedBidResponses, bidderImpReplaceImp, e := deps.loadRequestJSONForAmp(httpRequest) + reqNormal, storedAuctionResponses, storedBidResponses, bidderImpReplaceImp, e := deps.loadRequestJSONForAmp(httpRequest, labels) if errs = append(errs, e...); errortypes.ContainsFatalError(errs) { return } @@ -536,7 +536,7 @@ func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openr } // Load the stored OpenRTB request for an incoming AMP request, or return the errors found. -func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req *openrtb2.BidRequest, storedAuctionResponses stored_responses.ImpsWithBidResponses, storedBidResponses stored_responses.ImpBidderStoredResp, bidderImpReplaceImp stored_responses.BidderImpReplaceImpID, errs []error) { +func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request, labels metrics.Labels) (req *openrtb2.BidRequest, storedAuctionResponses stored_responses.ImpsWithBidResponses, storedBidResponses stored_responses.ImpBidderStoredResp, bidderImpReplaceImp stored_responses.BidderImpReplaceImpID, errs []error) { req = &openrtb2.BidRequest{} errs = nil @@ -559,6 +559,7 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req // The fetched config becomes the entire OpenRTB request requestJSON := storedRequests[ampParams.StoredRequestID] + labels.RequestSize = len(requestJSON) if err := jsonutil.UnmarshalValid(requestJSON, req); err != nil { errs = []error{err} return diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 14f2fdee55..692d92733f 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -442,6 +442,7 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metric errs = []error{err} return } + labels.RequestSize = len(requestJson) if limitedReqReader.N <= 0 { // Limited Reader returns 0 if the request was exactly at the max size or over the limit. diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index 0bad62124d..65b5fd520a 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -176,6 +176,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re handleError(&labels, w, []error{err}, &vo, &debugLog) return } + labels.RequestSize = len(requestJson) resolvedRequest := requestJson if debugLog.DebugEnabledOrOverridden { diff --git a/metrics/config/metrics_test.go b/metrics/config/metrics_test.go index 6060b692bf..48166f07fc 100644 --- a/metrics/config/metrics_test.go +++ b/metrics/config/metrics_test.go @@ -53,6 +53,7 @@ func TestMultiMetricsEngine(t *testing.T) { PubID: "test1", CookieFlag: metrics.CookieFlagYes, RequestStatus: metrics.RequestStatusOK, + RequestSize: 1024, } apnLabels := metrics.AdapterLabels{ Source: metrics.DemandWeb, @@ -157,6 +158,9 @@ func TestMultiMetricsEngine(t *testing.T) { VerifyMetrics(t, "RequestStatuses.OpenRTB2.BadInput", goEngine.RequestStatuses[metrics.ReqTypeORTB2Web][metrics.RequestStatusBadInput].Count(), 0) VerifyMetrics(t, "RequestStatuses.OpenRTB2.BlockedApp", goEngine.RequestStatuses[metrics.ReqTypeORTB2Web][metrics.RequestStatusBlockedApp].Count(), 0) + VerifyMetrics(t, "RequestSizeByEndpoint.Auction", goEngine.RequestSizeByEndpoint[metrics.EndpointAuction].Count(), 5) + VerifyMetrics(t, "RequestSizeByEndpoint.Auction", goEngine.RequestSizeByEndpoint[metrics.EndpointAuction].Max(), 1024) + VerifyMetrics(t, "ImpsTypeBanner", goEngine.ImpsTypeBanner.Count(), 5) VerifyMetrics(t, "ImpsTypeVideo", goEngine.ImpsTypeVideo.Count(), 3) VerifyMetrics(t, "ImpsTypeAudio", goEngine.ImpsTypeAudio.Count(), 5) diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index aa98b18415..4bff20622f 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -41,6 +41,7 @@ type Metrics struct { // Metrics for OpenRTB requests specifically RequestStatuses map[RequestType]map[RequestStatus]metrics.Meter + RequestSizeByEndpoint map[EndpointType]metrics.Histogram AmpNoCookieMeter metrics.Meter CookieSyncMeter metrics.Meter CookieSyncStatusMeter map[CookieSyncStatus]metrics.Meter @@ -159,6 +160,7 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr newMetrics := &Metrics{ MetricsRegistry: registry, RequestStatuses: make(map[RequestType]map[RequestStatus]metrics.Meter), + RequestSizeByEndpoint: make(map[EndpointType]metrics.Histogram), ConnectionCounter: metrics.NilCounter{}, ConnectionAcceptErrorMeter: blankMeter, ConnectionCloseErrorMeter: blankMeter, @@ -235,6 +237,12 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr } } + for _, t := range EndpointTypes() { + if t != EndpointAmp { + newMetrics.RequestSizeByEndpoint[t] = &metrics.NilHistogram{} + } + } + for _, c := range CacheResults() { newMetrics.StoredReqCacheMeter[c] = blankMeter newMetrics.StoredImpCacheMeter[c] = blankMeter @@ -358,6 +366,10 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d } } + for _, endpoint := range EndpointTypes() { + newMetrics.RequestSizeByEndpoint[endpoint] = metrics.GetOrRegisterHistogram("requests.size."+string(endpoint), registry, metrics.NewUniformSample(1024)) + } + for _, cacheRes := range CacheResults() { newMetrics.StoredReqCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_request_cache_%s", string(cacheRes)), registry) newMetrics.StoredImpCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_imp_cache_%s", string(cacheRes)), registry) @@ -612,6 +624,11 @@ func (me *Metrics) RecordRequest(labels Labels) { } } + // Request size by endpoint + if labels.RequestSize > 0 && labels.RType != ReqTypeAMP { + me.RequestSizeByEndpoint[GetEndpointFromRequestType(labels.RType)].Update(int64(labels.RequestSize)) + } + // Handle the account metrics now. am := me.getAccountMetrics(labels.PubID) am.requestMeter.Mark(1) diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index a5283a35c2..33fef15652 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -57,6 +57,8 @@ func TestNewMetrics(t *testing.T) { ensureContains(t, registry, "requests.badinput.video", m.RequestStatuses[ReqTypeVideo][RequestStatusBadInput]) ensureContains(t, registry, "requests.err.video", m.RequestStatuses[ReqTypeVideo][RequestStatusErr]) ensureContains(t, registry, "requests.networkerr.video", m.RequestStatuses[ReqTypeVideo][RequestStatusNetworkErr]) + ensureContains(t, registry, "requests.size.auction", m.RequestSizeByEndpoint[EndpointAuction]) + ensureContains(t, registry, "requests.size.video", m.RequestSizeByEndpoint[EndpointVideo]) ensureContains(t, registry, "queued_requests.video.rejected", m.RequestsQueueTimer[ReqTypeVideo][false]) ensureContains(t, registry, "queued_requests.video.accepted", m.RequestsQueueTimer[ReqTypeVideo][true]) diff --git a/metrics/metrics.go b/metrics/metrics.go index 71c02a7557..4e4ab841d6 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -13,6 +13,7 @@ type Labels struct { PubID string // exchange specific ID, so we cannot compile in values CookieFlag CookieFlag RequestStatus RequestStatus + RequestSize int } // AdapterLabels defines the labels that can be attached to the adapter metrics. @@ -139,6 +140,8 @@ type DemandSource string // ImpMediaType : Media type described in the "imp" JSON object TODO is this still needed? type ImpMediaType string +type EndpointType string + // RequestType : Request type enumeration type RequestType string @@ -196,6 +199,40 @@ func RequestTypes() []RequestType { } } +// Endpoint type constants +const ( + EndpointAuction EndpointType = "auction" + EndpointVideo EndpointType = "video" + EndpointAmp EndpointType = "amp" +) + +func EndpointTypes() []EndpointType { + return []EndpointType{ + EndpointAuction, + EndpointVideo, + EndpointAmp, + } +} + +func GetEndpointFromRequestType(requestType RequestType) EndpointType { + var requestEndpoint EndpointType + + switch requestType { + case ReqTypeORTB2Web: + fallthrough + case ReqTypeORTB2App: + fallthrough + case ReqTypeORTB2DOOH: + requestEndpoint = EndpointAuction + case ReqTypeAMP: + requestEndpoint = EndpointAmp + case ReqTypeVideo: + requestEndpoint = EndpointVideo + } + + return requestEndpoint +} + // The media types described in the "imp" json objects const ( ImpTypeBanner ImpMediaType = "banner" diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go new file mode 100644 index 0000000000..eef7eeed8c --- /dev/null +++ b/metrics/metrics_test.go @@ -0,0 +1,49 @@ +package metrics + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetEndpointFromRequestType(t *testing.T) { + testCases := []struct { + name string + inRequestType RequestType + expected EndpointType + }{ + { + name: "request-type-openrtb2-web", + inRequestType: ReqTypeORTB2Web, + expected: EndpointAuction, + }, + { + name: "request-type-openrtb2-app", + inRequestType: ReqTypeORTB2App, + expected: EndpointAuction, + }, + { + name: "request-type-openrtb2-dooh", + inRequestType: ReqTypeORTB2DOOH, + expected: EndpointAuction, + }, + { + name: "request-type-amp", + inRequestType: ReqTypeAMP, + expected: EndpointAmp, + }, + { + name: "request-type-video", + inRequestType: ReqTypeVideo, + expected: EndpointVideo, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out := GetEndpointFromRequestType(tc.inRequestType) + + assert.Equal(t, tc.expected, out) + }) + } +} diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index a2cc60f768..1746065413 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -30,6 +30,7 @@ type Metrics struct { impressions *prometheus.CounterVec prebidCacheWriteTimer *prometheus.HistogramVec requests *prometheus.CounterVec + requestsSize *prometheus.HistogramVec debugRequests prometheus.Counter requestsTimer *prometheus.HistogramVec requestsQueueTimer *prometheus.HistogramVec @@ -127,6 +128,7 @@ const ( privacyBlockedLabel = "privacy_blocked" requestStatusLabel = "request_status" requestTypeLabel = "request_type" + requestEndpointLabel = "request_size" stageLabel = "stage" statusLabel = "status" successLabel = "success" @@ -171,6 +173,7 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet priceBuckets := []float64{250, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000} queuedRequestTimeBuckets := []float64{0, 1, 5, 30, 60, 120, 180, 240, 300} overheadTimeBuckets := []float64{0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1} + requestSizeBuckets := []float64{100, 500, 750, 1000, 2000, 4000, 7000, 10000, 15000, 20000, 50000, 75000} metrics := Metrics{} reg := prometheus.NewRegistry() @@ -227,6 +230,11 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "Count of total requests to Prebid Server labeled by type and status.", []string{requestTypeLabel, requestStatusLabel}) + metrics.requestsSize = newHistogramVec(cfg, reg, + "request_size_bytes", + "Count that keeps track of incoming request size in bytes labeled by endpoint.", + []string{requestEndpointLabel}, requestSizeBuckets) + metrics.debugRequests = newCounterWithoutLabels(cfg, reg, "debug_requests", "Count of total requests to Prebid Server that have debug enabled") @@ -682,6 +690,13 @@ func (m *Metrics) RecordRequest(labels metrics.Labels) { requestStatusLabel: string(labels.RequestStatus), }).Inc() + if labels.RequestSize > 0 && labels.RType != metrics.ReqTypeAMP { + endpoint := metrics.GetEndpointFromRequestType(labels.RType) + m.requestsSize.With(prometheus.Labels{ + requestEndpointLabel: string(endpoint), + }).Observe(float64(labels.RequestSize)) + } + if labels.CookieFlag == metrics.CookieFlagNo { m.requestsWithoutCookie.With(prometheus.Labels{ requestTypeLabel: string(labels.RType), diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index 7ab1fb6502..f52a8ec11d 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -166,6 +166,7 @@ func TestRequestMetric(t *testing.T) { m.RecordRequest(metrics.Labels{ RType: requestType, RequestStatus: requestStatus, + RequestSize: 1024, }) expectedCount := float64(1) @@ -175,6 +176,9 @@ func TestRequestMetric(t *testing.T) { requestTypeLabel: string(requestType), requestStatusLabel: string(requestStatus), }) + + histogram := getHistogramFromHistogramVec(m.requestsSize, requestEndpointLabel, string(metrics.EndpointAuction)) + assertHistogram(t, "requests_size_auction", histogram, 1, 1024) } func TestDebugRequestMetric(t *testing.T) { From 93c17c2218fda17c8230880c999bbeb54a794917 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com> Date: Mon, 8 Sep 2025 14:47:15 -0700 Subject: [PATCH 074/272] Modules: Execute mutations in the order they are listed (#4279) * 4278 Execute mutations in the sequence they are listed. * Ensure that the rejected channel is closed (once) on reject * Use stack var. * Add comments. * Ensure rejected is closed. * Just return explicitly in all 3 cases. * Keep the same style - of passing the params to the go routine. --- hooks/hookexecution/execution.go | 55 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go index 182af44dbd..d0c7815f03 100644 --- a/hooks/hookexecution/execution.go +++ b/hooks/hookexecution/execution.go @@ -69,38 +69,45 @@ func executeGroup[H any, P any]( ) (GroupOutcome, P, groupModuleContext, *RejectError) { var wg sync.WaitGroup rejected := make(chan struct{}) - resp := make(chan hookResponse[P], len(group.Hooks)) + var rejectedOnce sync.Once + closeRejectedOnce := func() { + rejectedOnce.Do(func() { + close(rejected) + }) + } + // Ensure the channel is closed when the function returns. + defer closeRejectedOnce() + hookResponses := make([]hookResponse[P], len(group.Hooks)) - for _, hook := range group.Hooks { + for i, hook := range group.Hooks { mCtx := executionCtx.getModuleContext(hook.Module) mCtx.HookImplCode = hook.Code newPayload := handleModuleActivities(hook.Code, executionCtx.activityControl, payload, executionCtx.account) wg.Add(1) - go func(hw hooks.HookWrapper[H], moduleCtx hookstage.ModuleInvocationContext) { + go func(hw hooks.HookWrapper[H], hookResp *hookResponse[P], moduleCtx hookstage.ModuleInvocationContext) { defer wg.Done() - executeHook(moduleCtx, hw, newPayload, hookHandler, group.Timeout, resp, rejected) - }(hook, mCtx) + if executeHook(moduleCtx, hw, newPayload, hookHandler, group.Timeout, hookResp, rejected) { + // When the first hook rejects, close the channel to signal all other hooks to stop. + closeRejectedOnce() + } + }(hook, &hookResponses[i], mCtx) } - go func() { - wg.Wait() - close(resp) - }() - - hookResponses := collectHookResponses(resp, rejected) + wg.Wait() return handleHookResponses(executionCtx, hookResponses, payload, metricEngine) } +// executeHook executes a single hook and returns the rejected status. func executeHook[H any, P any]( moduleCtx hookstage.ModuleInvocationContext, hw hooks.HookWrapper[H], payload P, hookHandler hookHandler[H, P], timeout time.Duration, - resp chan<- hookResponse[P], + resp *hookResponse[P], rejected <-chan struct{}, -) { +) bool { hookRespCh := make(chan hookResponse[P], 1) startTime := time.Now() hookId := HookID{ModuleCode: hw.Module, HookImplCode: hw.Code} @@ -126,32 +133,22 @@ func executeHook[H any, P any]( case res := <-hookRespCh: res.HookID = hookId res.ExecutionTime = time.Since(startTime) - resp <- res + *resp = res + return res.Result.Reject case <-time.After(timeout): - resp <- hookResponse[P]{ + *resp = hookResponse[P]{ Err: TimeoutError{}, ExecutionTime: time.Since(startTime), HookID: hookId, Result: hookstage.HookResult[P]{}, } + return false case <-rejected: - return + // In this path, rejected has already been reported; no need to report it again. + return false } } -func collectHookResponses[P any](resp <-chan hookResponse[P], rejected chan<- struct{}) []hookResponse[P] { - hookResponses := make([]hookResponse[P], 0) - for r := range resp { - hookResponses = append(hookResponses, r) - if r.Result.Reject { - close(rejected) - break - } - } - - return hookResponses -} - func handleHookResponses[P any]( executionCtx executionContext, hookResponses []hookResponse[P], From 5da447c3d7c5637358a0255bb3b6c6fd78307ddd Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Thu, 11 Sep 2025 14:07:27 -0400 Subject: [PATCH 075/272] Revert "Modules: Execute mutations in the order they are listed (#4279)" (#4529) This reverts commit 93c17c2218fda17c8230880c999bbeb54a794917. --- hooks/hookexecution/execution.go | 55 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go index d0c7815f03..182af44dbd 100644 --- a/hooks/hookexecution/execution.go +++ b/hooks/hookexecution/execution.go @@ -69,45 +69,38 @@ func executeGroup[H any, P any]( ) (GroupOutcome, P, groupModuleContext, *RejectError) { var wg sync.WaitGroup rejected := make(chan struct{}) - var rejectedOnce sync.Once - closeRejectedOnce := func() { - rejectedOnce.Do(func() { - close(rejected) - }) - } - // Ensure the channel is closed when the function returns. - defer closeRejectedOnce() - hookResponses := make([]hookResponse[P], len(group.Hooks)) + resp := make(chan hookResponse[P], len(group.Hooks)) - for i, hook := range group.Hooks { + for _, hook := range group.Hooks { mCtx := executionCtx.getModuleContext(hook.Module) mCtx.HookImplCode = hook.Code newPayload := handleModuleActivities(hook.Code, executionCtx.activityControl, payload, executionCtx.account) wg.Add(1) - go func(hw hooks.HookWrapper[H], hookResp *hookResponse[P], moduleCtx hookstage.ModuleInvocationContext) { + go func(hw hooks.HookWrapper[H], moduleCtx hookstage.ModuleInvocationContext) { defer wg.Done() - if executeHook(moduleCtx, hw, newPayload, hookHandler, group.Timeout, hookResp, rejected) { - // When the first hook rejects, close the channel to signal all other hooks to stop. - closeRejectedOnce() - } - }(hook, &hookResponses[i], mCtx) + executeHook(moduleCtx, hw, newPayload, hookHandler, group.Timeout, resp, rejected) + }(hook, mCtx) } - wg.Wait() + go func() { + wg.Wait() + close(resp) + }() + + hookResponses := collectHookResponses(resp, rejected) return handleHookResponses(executionCtx, hookResponses, payload, metricEngine) } -// executeHook executes a single hook and returns the rejected status. func executeHook[H any, P any]( moduleCtx hookstage.ModuleInvocationContext, hw hooks.HookWrapper[H], payload P, hookHandler hookHandler[H, P], timeout time.Duration, - resp *hookResponse[P], + resp chan<- hookResponse[P], rejected <-chan struct{}, -) bool { +) { hookRespCh := make(chan hookResponse[P], 1) startTime := time.Now() hookId := HookID{ModuleCode: hw.Module, HookImplCode: hw.Code} @@ -133,22 +126,32 @@ func executeHook[H any, P any]( case res := <-hookRespCh: res.HookID = hookId res.ExecutionTime = time.Since(startTime) - *resp = res - return res.Result.Reject + resp <- res case <-time.After(timeout): - *resp = hookResponse[P]{ + resp <- hookResponse[P]{ Err: TimeoutError{}, ExecutionTime: time.Since(startTime), HookID: hookId, Result: hookstage.HookResult[P]{}, } - return false case <-rejected: - // In this path, rejected has already been reported; no need to report it again. - return false + return } } +func collectHookResponses[P any](resp <-chan hookResponse[P], rejected chan<- struct{}) []hookResponse[P] { + hookResponses := make([]hookResponse[P], 0) + for r := range resp { + hookResponses = append(hookResponses, r) + if r.Result.Reject { + close(rejected) + break + } + } + + return hookResponses +} + func handleHookResponses[P any]( executionCtx executionContext, hookResponses []hookResponse[P], From 17a06b6ac6691aebae3782b25e9921cfb42c8683 Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Thu, 18 Sep 2025 18:36:08 -0400 Subject: [PATCH 076/272] Revert "Metrics: Record HTTP connections wanted and obtained (#4518)" (#4538) --- exchange/bidder.go | 2 -- exchange/bidder_test.go | 2 -- metrics/config/metrics.go | 18 ------------------ metrics/go_metrics.go | 14 -------------- metrics/go_metrics_test.go | 2 -- metrics/metrics.go | 2 -- metrics/metrics_mock.go | 8 -------- metrics/prometheus/prometheus.go | 18 ------------------ metrics/prometheus/prometheus_test.go | 20 -------------------- 9 files changed, 86 deletions(-) diff --git a/exchange/bidder.go b/exchange/bidder.go index c0c748b9b5..a305a0e84b 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -735,7 +735,6 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context // GetConn is called before a connection is created or retrieved from an idle pool GetConn: func(hostPort string) { connStart = time.Now() - bidder.me.RecordConnectionWant() }, // GotConn is called after a successful connection is obtained GotConn: func(info httptrace.GotConnInfo) { @@ -753,7 +752,6 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context } bidder.me.RecordAdapterConnections(bidder.BidderName, info.Reused, connWaitTime) - bidder.me.RecordConnectionGot() }, // DNSStart is called when a DNS lookup begins. DNSStart: func(info httptrace.DNSStartInfo) { diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index e8e0b5a8b9..50e919c2a6 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -2085,8 +2085,6 @@ func TestCallRecordAdapterConnections(t *testing.T) { mockMetricEngine.On("RecordAdapterConnections", expectedAdapterName, false, mock.MatchedBy(compareConnWaitTime)).Once() mockMetricEngine.On("RecordOverheadTime", metrics.PreBidder, mock.Anything).Once() mockMetricEngine.On("RecordBidderServerResponseTime", mock.Anything).Once() - mockMetricEngine.On("RecordConnectionWant").Once() - mockMetricEngine.On("RecordConnectionGot").Once() // Run requestBid using an http.Client with a mock handler bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, mockMetricEngine, openrtb_ext.BidderAppnexus, nil, "") diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index 4256e8125c..1a378e0faf 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -384,18 +384,6 @@ func (me *MultiMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderN } } -func (me *MultiMetricsEngine) RecordConnectionWant() { - for _, thisME := range *me { - thisME.RecordConnectionWant() - } -} - -func (me *MultiMetricsEngine) RecordConnectionGot() { - for _, thisME := range *me { - thisME.RecordConnectionGot() - } -} - // NilMetricsEngine implements the MetricsEngine interface where no metrics are actually captured. This is // used if no metric backend is configured and also for tests. type NilMetricsEngine struct{} @@ -578,9 +566,3 @@ func (me *NilMetricsEngine) RecordModuleTimeout(labels metrics.ModuleLabels) { // RecordAdapterThrottled as a noop func (me *NilMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderName) { } - -func (me *NilMetricsEngine) RecordConnectionWant() { -} - -func (me *NilMetricsEngine) RecordConnectionGot() { -} diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index 4bff20622f..e6fa3ec550 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -18,8 +18,6 @@ type Metrics struct { TMaxTimeoutCounter metrics.Counter ConnectionAcceptErrorMeter metrics.Meter ConnectionCloseErrorMeter metrics.Meter - ConnectionWantCounter metrics.Counter - ConnectionGotCounter metrics.Counter ImpMeter metrics.Meter AppRequestMeter metrics.Meter NoCookieMeter metrics.Meter @@ -164,8 +162,6 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr ConnectionCounter: metrics.NilCounter{}, ConnectionAcceptErrorMeter: blankMeter, ConnectionCloseErrorMeter: blankMeter, - ConnectionWantCounter: metrics.NilCounter{}, - ConnectionGotCounter: metrics.NilCounter{}, ImpMeter: blankMeter, AppRequestMeter: blankMeter, DebugRequestMeter: blankMeter, @@ -299,8 +295,6 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d newMetrics.TMaxTimeoutCounter = metrics.GetOrRegisterCounter("tmax_timeout", registry) newMetrics.ConnectionAcceptErrorMeter = metrics.GetOrRegisterMeter("connection_accept_errors", registry) newMetrics.ConnectionCloseErrorMeter = metrics.GetOrRegisterMeter("connection_close_errors", registry) - newMetrics.ConnectionWantCounter = metrics.GetOrRegisterCounter("connection_want", registry) - newMetrics.ConnectionGotCounter = metrics.GetOrRegisterCounter("connection_got", registry) newMetrics.ImpMeter = metrics.GetOrRegisterMeter("imps_requested", registry) newMetrics.ImpsTypeBanner = metrics.GetOrRegisterMeter("imp_banner", registry) @@ -693,14 +687,6 @@ func (me *Metrics) RecordConnectionClose(success bool) { } } -func (me *Metrics) RecordConnectionWant() { - me.ConnectionWantCounter.Inc(1) -} - -func (me *Metrics) RecordConnectionGot() { - me.ConnectionGotCounter.Inc(1) -} - // RecordRequestTime implements a part of the MetricsEngine interface. The calling code is responsible // for determining the call duration. func (me *Metrics) RecordRequestTime(labels Labels, length time.Duration) { diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index 33fef15652..e32bf930c1 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -88,8 +88,6 @@ func TestNewMetrics(t *testing.T) { ensureContains(t, registry, "request_over_head_time.make-bidder-requests", m.OverheadTimer[MakeBidderRequests]) ensureContains(t, registry, "bidder_server_response_time_seconds", m.BidderServerResponseTimer) ensureContains(t, registry, "tmax_timeout", m.TMaxTimeoutCounter) - ensureContains(t, registry, "connection_want", m.ConnectionWantCounter) - ensureContains(t, registry, "connection_got", m.ConnectionGotCounter) for module, stages := range moduleStageNames { for _, stage := range stages { diff --git a/metrics/metrics.go b/metrics/metrics.go index 4e4ab841d6..c4079c3fe6 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -511,6 +511,4 @@ type MetricsEngine interface { RecordModuleExecutionError(labels ModuleLabels) RecordModuleTimeout(labels ModuleLabels) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) - RecordConnectionWant() - RecordConnectionGot() } diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index f33bd7bf99..911bcaf4b6 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -234,11 +234,3 @@ func (me *MetricsEngineMock) RecordModuleTimeout(labels ModuleLabels) { func (me *MetricsEngineMock) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { me.Called(adapterName) } - -func (me *MetricsEngineMock) RecordConnectionWant() { - me.Called() -} - -func (me *MetricsEngineMock) RecordConnectionGot() { - me.Called() -} diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 1746065413..fb8c5ce2e5 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -23,8 +23,6 @@ type Metrics struct { connectionsClosed prometheus.Counter connectionsError *prometheus.CounterVec connectionsOpened prometheus.Counter - connectionWant prometheus.Counter - connectionGot prometheus.Counter cookieSync *prometheus.CounterVec setUid *prometheus.CounterVec impressions *prometheus.CounterVec @@ -192,14 +190,6 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "connections_opened", "Count of successful connections opened to Prebid Server.") - metrics.connectionWant = newCounterWithoutLabels(cfg, reg, - "connections_want", - "Count number of times client trace calls GetConn.") - - metrics.connectionGot = newCounterWithoutLabels(cfg, reg, - "connections_got", - "Count number of times client trace calls GotConn.") - metrics.tmaxTimeout = newCounterWithoutLabels(cfg, reg, "tmax_timeout", "Count of requests rejected due to Tmax timeout exceed.") @@ -1135,11 +1125,3 @@ func (m *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { adapterLabel: strings.ToLower(string(adapterName)), }).Inc() } - -func (m *Metrics) RecordConnectionWant() { - m.connectionWant.Inc() -} - -func (m *Metrics) RecordConnectionGot() { - m.connectionGot.Inc() -} diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index f52a8ec11d..78e9b01494 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -75,8 +75,6 @@ func TestConnectionMetrics(t *testing.T) { expectedOpenedErrorCount float64 expectedClosedCount float64 expectedClosedErrorCount float64 - expectedConnectionWant float64 - expectedConnectionGot float64 }{ { description: "Open Success", @@ -118,20 +116,6 @@ func TestConnectionMetrics(t *testing.T) { expectedClosedCount: 0, expectedClosedErrorCount: 1, }, - { - description: "connection-want", - testCase: func(m *Metrics) { - m.RecordConnectionWant() - }, - expectedConnectionWant: 1, - }, - { - description: "connection-got", - testCase: func(m *Metrics) { - m.RecordConnectionGot() - }, - expectedConnectionGot: 1, - }, } for _, test := range testCases { @@ -151,10 +135,6 @@ func TestConnectionMetrics(t *testing.T) { test.expectedClosedErrorCount, prometheus.Labels{ connectionErrorLabel: connectionCloseError, }) - assertCounterValue(t, test.description, "connectionWant", m.connectionWant, - test.expectedConnectionWant) - assertCounterValue(t, test.description, "connectionGot", m.connectionGot, - test.expectedConnectionGot) } } From 51c04c6439af10408d0f40f44236c96b73087b95 Mon Sep 17 00:00:00 2001 From: andreafassina <127768714+andreafassina@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:38:25 +0200 Subject: [PATCH 077/272] New Adapter: Nativery (#4321) Co-authored-by: Andrea Fassina <fasenderos@gmail.com> Co-authored-by: nicoladellamorte <nicola.dellamorte@nativery.com> --- adapters/nativery/nativery.go | 267 +++++++++++++ adapters/nativery/nativery_test.go | 20 + .../nativery/nativerytest/amp/banner.json | 140 +++++++ .../amp/multi-format-multi-imp-type.json | 372 ++++++++++++++++++ .../nativery/nativerytest/amp/native.json | 130 ++++++ adapters/nativery/nativerytest/amp/video.json | 138 +++++++ .../nativerytest/exemplary/banner-app.json | 154 ++++++++ .../exemplary/banner-no-currency.json | 139 +++++++ .../nativerytest/exemplary/banner.json | 140 +++++++ .../multi-format-multi-imp-type.json | 372 ++++++++++++++++++ .../exemplary/native-no-currency.json | 129 ++++++ .../nativerytest/exemplary/native.json | 130 ++++++ .../exemplary/video-no-currency.json | 137 +++++++ .../nativerytest/exemplary/video.json | 138 +++++++ .../supplemental/bad_bid_response.json | 74 ++++ .../supplemental/invalid_bid_media_type.json | 113 ++++++ .../supplemental/invalid_imp.json | 64 +++ .../supplemental/invalid_imp_ext.json | 34 ++ .../supplemental/invalid_response.json | 79 ++++ .../supplemental/invalid_widget_id.json | 29 ++ .../supplemental/missing_widget_id.json | 57 +++ .../nativerytest/supplemental/status_204.json | 90 +++++ .../status_204_nativery_error.json | 88 +++++ .../nativerytest/supplemental/status_400.json | 87 ++++ adapters/nativery/params_test.go | 49 +++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_nativery.go | 5 + static/bidder-info/nativery.yaml | 12 + static/bidder-params/nativery.json | 15 + 30 files changed, 3206 insertions(+) create mode 100644 adapters/nativery/nativery.go create mode 100644 adapters/nativery/nativery_test.go create mode 100644 adapters/nativery/nativerytest/amp/banner.json create mode 100644 adapters/nativery/nativerytest/amp/multi-format-multi-imp-type.json create mode 100644 adapters/nativery/nativerytest/amp/native.json create mode 100644 adapters/nativery/nativerytest/amp/video.json create mode 100644 adapters/nativery/nativerytest/exemplary/banner-app.json create mode 100644 adapters/nativery/nativerytest/exemplary/banner-no-currency.json create mode 100644 adapters/nativery/nativerytest/exemplary/banner.json create mode 100644 adapters/nativery/nativerytest/exemplary/multi-format-multi-imp-type.json create mode 100644 adapters/nativery/nativerytest/exemplary/native-no-currency.json create mode 100644 adapters/nativery/nativerytest/exemplary/native.json create mode 100644 adapters/nativery/nativerytest/exemplary/video-no-currency.json create mode 100644 adapters/nativery/nativerytest/exemplary/video.json create mode 100644 adapters/nativery/nativerytest/supplemental/bad_bid_response.json create mode 100644 adapters/nativery/nativerytest/supplemental/invalid_bid_media_type.json create mode 100644 adapters/nativery/nativerytest/supplemental/invalid_imp.json create mode 100644 adapters/nativery/nativerytest/supplemental/invalid_imp_ext.json create mode 100644 adapters/nativery/nativerytest/supplemental/invalid_response.json create mode 100644 adapters/nativery/nativerytest/supplemental/invalid_widget_id.json create mode 100644 adapters/nativery/nativerytest/supplemental/missing_widget_id.json create mode 100644 adapters/nativery/nativerytest/supplemental/status_204.json create mode 100644 adapters/nativery/nativerytest/supplemental/status_204_nativery_error.json create mode 100644 adapters/nativery/nativerytest/supplemental/status_400.json create mode 100644 adapters/nativery/params_test.go create mode 100644 openrtb_ext/imp_nativery.go create mode 100644 static/bidder-info/nativery.yaml create mode 100644 static/bidder-params/nativery.json diff --git a/adapters/nativery/nativery.go b/adapters/nativery/nativery.go new file mode 100644 index 0000000000..1cd05aac12 --- /dev/null +++ b/adapters/nativery/nativery.go @@ -0,0 +1,267 @@ +package nativery + +import ( + "fmt" + "maps" + "net/http" + + "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/metrics" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type bidReqExtNativery struct { + IsAMP bool `json:"isAmp"` + WidgetId string `json:"widgetId"` +} + +type bidExtNativery struct { + BidType string `json:"bid_ad_media_type"` + BidAdvDomains []string `json:"bid_adv_domains"` + + AdvertiserId string `json:"adv_id,omitempty"` + BrandCategory int `json:"brand_category_id,omitempty"` +} + +type bidExt struct { + Nativery bidExtNativery `json:"nativery"` +} + +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) { + reqCopy := *request + var errs []error + + // check if the request come from AMP + var isAMP int + if reqInfo.PbsEntryPoint == metrics.ReqTypeAMP { + isAMP = 1 + } + + var widgetId string + + // attach body request for all the impressions + validImps := make([]openrtb2.Imp, 0, len(request.Imp)) + for i, imp := range request.Imp { + nativeryExt, err := buildNativeryExt(&imp) + + if err != nil { + errs = append(errs, err) + continue + } + + if i == 0 { + widgetId = nativeryExt.WidgetId + } + + validImps = append(validImps, imp) + } + + reqCopy.Imp = validImps + if len(reqCopy.Imp) == 0 { + return nil, errs + } + + reqExt, err := getRequestExt(reqCopy.Ext) + if err != nil { + return nil, append(errs, err) + } + + reqExtNativery, err := getNativeryExt(reqExt, isAMP, widgetId) + if err != nil { + return nil, append(errs, err) + } + adapterRequests, splitErrors := splitRequests(reqCopy.Imp, &reqCopy, reqExt, reqExtNativery, a.endpoint) + + return adapterRequests, append(errs, splitErrors...) +} + +func buildNativeryExt(imp *openrtb2.Imp) (openrtb_ext.ImpExtNativery, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return openrtb_ext.ImpExtNativery{}, err + } + + var nativeryExt openrtb_ext.ImpExtNativery + if err := jsonutil.Unmarshal(bidderExt.Bidder, &nativeryExt); err != nil { + return openrtb_ext.ImpExtNativery{}, err + } + + return nativeryExt, nil +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + nativeryError := response.Headers.Get("X-Nativery-Error") + if nativeryError != "" { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Nativery Error: %s.", nativeryError), + }} + } + + return nil, []error{&errortypes.BadServerResponse{ + Message: "No Content", + }} + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var nativeryResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &nativeryResponse); err != nil { + return nil, []error{err} + } + + var errs []error + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) + for _, sb := range nativeryResponse.SeatBid { + for i := range sb.Bid { + bid := sb.Bid[i] + + var bidExt bidExt + if err := jsonutil.Unmarshal(bid.Ext, &bidExt); err != nil { + errs = append(errs, err) + continue + } + + bidType, err := getMediaTypeForBid(&bidExt) + if err != nil { + errs = append(errs, err) + continue + } + bidMeta := buildBidMeta(string(bidType), bidExt.Nativery.BidAdvDomains) + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + BidMeta: bidMeta, + }) + } + + } + + if nativeryResponse.Cur != "" { + bidderResponse.Currency = nativeryResponse.Cur + } else { + bidderResponse.Currency = "EUR" + } + return bidderResponse, errs + +} + +func getMediaTypeForBid(bid *bidExt) (openrtb_ext.BidType, error) { + switch bid.Nativery.BidType { + case "native": + return openrtb_ext.BidTypeNative, nil + case "display", "banner", "rich_media": + return openrtb_ext.BidTypeBanner, nil + case "video": + return openrtb_ext.BidTypeVideo, nil + default: + return "", fmt.Errorf("unrecognized bid_ad_media_type in response from nativery: %s", bid.Nativery.BidType) + } +} + +func buildBidMeta(mediaType string, advDomain []string) *openrtb_ext.ExtBidPrebidMeta { + + return &openrtb_ext.ExtBidPrebidMeta{ + MediaType: mediaType, + AdvertiserDomains: advDomain, + } +} + +func splitRequests( + imps []openrtb2.Imp, + request *openrtb2.BidRequest, + requestExt map[string]jsonutil.RawMessage, + requestExtNativery bidReqExtNativery, + uri string, +) ([]*adapters.RequestData, []error) { + var errs []error + + resArr := make([]*adapters.RequestData, 0, len(imps)) + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + nativeryExtJson, err := jsonutil.Marshal(requestExtNativery) + if err != nil { + errs = append(errs, err) + } + + baseReq := *request + + for _, imp := range imps { + extClone := maps.Clone(requestExt) + extClone["nativery"] = nativeryExtJson + + reqCopy := baseReq + + reqCopy.Ext, err = jsonutil.Marshal(extClone) + if err != nil { + errs = append(errs, err) + continue + } + + reqCopy.Imp = []openrtb2.Imp{imp} + + reqJSON, err := jsonutil.Marshal(&reqCopy) + if err != nil { + errs = append(errs, err) + continue + } + + resArr = append(resArr, &adapters.RequestData{ + Method: "POST", + Uri: uri, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(reqCopy.Imp), + }) + } + + return resArr, errs +} + +func getRequestExt(ext jsonutil.RawMessage) (map[string]jsonutil.RawMessage, error) { + extMap := make(map[string]jsonutil.RawMessage) + + if len(ext) > 0 { + if err := jsonutil.Unmarshal(ext, &extMap); err != nil { + return nil, err + } + } + + return extMap, nil +} + +func getNativeryExt(extMap map[string]jsonutil.RawMessage, isAMP int, widgetId string) (bidReqExtNativery, error) { + var nativeryExt bidReqExtNativery + + if nativeryExtJson, exists := extMap["nativery"]; exists && len(nativeryExtJson) > 0 { + if err := jsonutil.Unmarshal(nativeryExtJson, &nativeryExt); err != nil { + return nativeryExt, err + } + } + + nativeryExt.IsAMP = isAMP == 1 + nativeryExt.WidgetId = widgetId + + return nativeryExt, nil +} diff --git a/adapters/nativery/nativery_test.go b/adapters/nativery/nativery_test.go new file mode 100644 index 0000000000..4875089fea --- /dev/null +++ b/adapters/nativery/nativery_test.go @@ -0,0 +1,20 @@ +package nativery + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderNativery, config.Adapter{ + Endpoint: "http://example.com/hb"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "nativerytest", bidder) +} diff --git a/adapters/nativery/nativerytest/amp/banner.json b/adapters/nativery/nativerytest/amp/banner.json new file mode 100644 index 0000000000..254655da04 --- /dev/null +++ b/adapters/nativery/nativerytest/amp/banner.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": true, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/amp/multi-format-multi-imp-type.json b/adapters/nativery/nativerytest/amp/multi-format-multi-imp-type.json new file mode 100644 index 0000000000..5532824330 --- /dev/null +++ b/adapters/nativery/nativerytest/amp/multi-format-multi-imp-type.json @@ -0,0 +1,372 @@ +{ + "mockBidRequest": { + "id": "test-multi-request-id", + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { "widgetId": "1" } + } + }, + { + "id": "imp-native", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { "widgetId": "1" } + } + }, + { + "id": "imp-hybrid", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { "widgetId": "1" } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": true, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-banner", + "impid": "imp-banner", + "price": 800, + "adm": "<div>banner ad</div>", + "adomain": ["example.com"], + "cid": "cid-banner", + "crid": "crid-banner", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + }, + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": true, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-native", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-native"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-native", + "impid": "imp-native", + "price": 600, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click\"}}}", + "adomain": ["example.com"], + "cid": "cid-native", + "crid": "crid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + }, + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": true, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-hybrid", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-hybrid"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-hybrid-banner", + "impid": "imp-hybrid", + "price": 1000, + "adm": "<div>hybrid banner</div>", + "adomain": ["example.com"], + "cid": "cid-hybrid-banner", + "crid": "crid-hybrid-banner", + "cat": ["IAB13-4"], + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + { + "id": "bid-hybrid-native", + "impid": "imp-hybrid", + "price": 500, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click2\"}}}", + "adomain": ["example.com"], + "cid": "cid-hybrid-native", + "crid": "crid-hybrid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-banner", + "impid": "imp-banner", + "price": 800, + "adm": "<div>banner ad</div>", + "adomain": ["example.com"], + "cid": "cid-banner", + "crid": "crid-banner", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-native", + "impid": "imp-native", + "price": 600, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click\"}}}", + "adomain": ["example.com"], + "cid": "cid-native", + "crid": "crid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + }, + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-hybrid-banner", + "impid": "imp-hybrid", + "price": 1000, + "adm": "<div>hybrid banner</div>", + "adomain": ["example.com"], + "cid": "cid-hybrid-banner", + "crid": "crid-hybrid-banner", + "cat": ["IAB13-4"], + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-hybrid-native", + "impid": "imp-hybrid", + "price": 500, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click2\"}}}", + "adomain": ["example.com"], + "cid": "cid-hybrid-native", + "crid": "crid-hybrid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/amp/native.json b/adapters/nativery/nativerytest/amp/native.json new file mode 100644 index 0000000000..7d5b86aee4 --- /dev/null +++ b/adapters/nativery/nativerytest/amp/native.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": true, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/amp/video.json b/adapters/nativery/nativerytest/amp/video.json new file mode 100644 index 0000000000..e988e3f1d7 --- /dev/null +++ b/adapters/nativery/nativerytest/amp/video.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": true, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/banner-app.json b/adapters/nativery/nativerytest/exemplary/banner-app.json new file mode 100644 index 0000000000..45dfe824b2 --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/banner-app.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "app": { + "bundle": "com.app.awesome", + "name": "Amesome App", + "domain": "awesomeapp.com", + "id": "1" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "app": { + "bundle": "com.app.awesome", + "name": "Amesome App", + "domain": "awesomeapp.com", + "id": "1" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": [ + "awesomeapp.com" + ], + "cid": "test-cid", + "crid": "test-crid", + "cat": [ + "IAB13-4" + ], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": [ + "awesomeapp.com" + ], + "cid": "test-cid", + "crid": "test-crid", + "cat": [ + "IAB13-4" + ], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nativery/nativerytest/exemplary/banner-no-currency.json b/adapters/nativery/nativerytest/exemplary/banner-no-currency.json new file mode 100644 index 0000000000..974e3e3ad5 --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/banner-no-currency.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ], + "seat": "nat-123" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/banner.json b/adapters/nativery/nativerytest/exemplary/banner.json new file mode 100644 index 0000000000..8a59fe9a68 --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/banner.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "adm": "<div>ad</div>", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/multi-format-multi-imp-type.json b/adapters/nativery/nativerytest/exemplary/multi-format-multi-imp-type.json new file mode 100644 index 0000000000..0fad5510dc --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/multi-format-multi-imp-type.json @@ -0,0 +1,372 @@ +{ + "mockBidRequest": { + "id": "test-multi-request-id", + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { "widgetId": "1" } + } + }, + { + "id": "imp-native", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { "widgetId": "1" } + } + }, + { + "id": "imp-hybrid", + "banner": { + "format": [{ "w": 728, "h": 90 }] + }, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { "widgetId": "1" } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": false, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-banner", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-banner", + "impid": "imp-banner", + "price": 800, + "adm": "<div>banner ad</div>", + "adomain": ["example.com"], + "cid": "cid-banner", + "crid": "crid-banner", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + }, + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": false, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-native", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-native"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-native", + "impid": "imp-native", + "price": 600, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click\"}}}", + "adomain": ["example.com"], + "cid": "cid-native", + "crid": "crid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + }, + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-multi-request-id", + "ext": { + "nativery": { "isAmp": false, "widgetId": "1" } + }, + "imp": [ + { + "id": "imp-hybrid", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200}}],\"context\":1,\"plcmttype\":1}" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["imp-hybrid"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-multi-request-id", + "seatbid": [ + { + "seat": "nat-123", + "bid": [ + { + "id": "bid-hybrid-banner", + "impid": "imp-hybrid", + "price": 1000, + "adm": "<div>hybrid banner</div>", + "adomain": ["example.com"], + "cid": "cid-hybrid-banner", + "crid": "crid-hybrid-banner", + "cat": ["IAB13-4"], + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + { + "id": "bid-hybrid-native", + "impid": "imp-hybrid", + "price": 500, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click2\"}}}", + "adomain": ["example.com"], + "cid": "cid-hybrid-native", + "crid": "crid-hybrid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-banner", + "impid": "imp-banner", + "price": 800, + "adm": "<div>banner ad</div>", + "adomain": ["example.com"], + "cid": "cid-banner", + "crid": "crid-banner", + "cat": ["IAB13-4"], + "w": 300, + "h": 250, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-native", + "impid": "imp-native", + "price": 600, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click\"}}}", + "adomain": ["example.com"], + "cid": "cid-native", + "crid": "crid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + }, + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-hybrid-banner", + "impid": "imp-hybrid", + "price": 1000, + "adm": "<div>hybrid banner</div>", + "adomain": ["example.com"], + "cid": "cid-hybrid-banner", + "crid": "crid-hybrid-banner", + "cat": ["IAB13-4"], + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "display" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-hybrid-native", + "impid": "imp-hybrid", + "price": 500, + "adm": "{\"native\":{\"assets\":[…],\"link\":{\"url\":\"http://example.com/click2\"}}}", + "adomain": ["example.com"], + "cid": "cid-hybrid-native", + "crid": "crid-hybrid-native", + "cat": ["IAB15-1"], + "mtype": 3, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/native-no-currency.json b/adapters/nativery/nativerytest/exemplary/native-no-currency.json new file mode 100644 index 0000000000..63a30c9c3e --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/native-no-currency.json @@ -0,0 +1,129 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ], + "seat": "nat-123" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/native.json b/adapters/nativery/nativerytest/exemplary/native.json new file mode 100644 index 0000000000..0ba6ef3317 --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/native.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"context\":1,\"plcmttype\":1,\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3,\"w\":120,\"h\":100}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"data\":{\"type\":1}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1]}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":3,\"required\":1,\"img\":{\"url\":\"http://example.com/img/url\",\"w\":120,\"h\":100}},{\"id\":0,\"required\":1,\"title\":{\"text\":\"Test title\"}},{\"id\":5,\"data\":{\"value\":\"Test sponsor\"}}],\"link\":{\"url\":\"http://example.com/click/url\"},\"imptrackers\":[\"http://example.com/impression\"],\"jstracker\":\"\\u003cscript src=\\\"http://example.com/impression\\\"\\u003e\\u003c/script\\u003e\"}", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 4, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/video-no-currency.json b/adapters/nativery/nativerytest/exemplary/video-no-currency.json new file mode 100644 index 0000000000..599937ba09 --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/video-no-currency.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + } + ], + "seat": "nat-123" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/exemplary/video.json b/adapters/nativery/nativerytest/exemplary/video.json new file mode 100644 index 0000000000..61ed00e95b --- /dev/null +++ b/adapters/nativery/nativerytest/exemplary/video.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + } + ], + "seat": "nat-123" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1000, + "nurl": "http://example.com/win/1000", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"4.0\"> ...", + "adomain": ["example.com"], + "cid": "test-cid", + "crid": "test-crid", + "cat": ["IAB13-4"], + "mtype": 2, + "ext": { + "nativery": { + "adv_id": "1", + "brand_category_id": 1, + "bid_ad_media_type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/nativery/nativerytest/supplemental/bad_bid_response.json b/adapters/nativery/nativerytest/supplemental/bad_bid_response.json new file mode 100644 index 0000000000..6003e6e82e --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/bad_bid_response.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "bad-bid-ext", + "imp": [ + { + "id": "1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "widgetId": "123" } } + } + ], + "site": { "page": "http://example.com", "ref": "http://example.com" }, + "device": { "ua": "ua", "h": 100, "w": 200 } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://example.com/hb", + "body": { + "id": "bad-bid-ext", + "imp": [ + { + "id": "1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "widgetId": "123" } } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { "ua": "ua", "h": 100, "w": 200 }, + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "123" + } + } + }, + "impIDs": ["1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "r", + "seatbid": [ + { + "bid": [ + { + "id": "b1", + "impid": "1", + "price": 1.2, + "adm": "<div></div>", + "ext": 123 + } + ] + } + ] + } + } + } + ], + "expectedRequestCount": 1, + "expectedMakeRequestsErrors": [], + "expectedMakeBidsErrors": [ + { "value": "expect { or n, but found", "comparison": "startswith" } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [] + } + ] +} diff --git a/adapters/nativery/nativerytest/supplemental/invalid_bid_media_type.json b/adapters/nativery/nativerytest/supplemental/invalid_bid_media_type.json new file mode 100644 index 0000000000..e3944109b1 --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/invalid_bid_media_type.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "err-unknown-type", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "ua", + "h": 100, + "w": 200 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "impIDs": ["imp-1"], + "body": { + "id": "err-unknown-type", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "ua", + "h": 100, + "w": 200 + }, + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "err-unknown-type", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "imp-1", + "price": 1.23, + "adm": "<div></div>", + "adomain": ["example.com"], + "cid": "cid", + "crid": "crid", + "cat": ["IAB1"], + "w": 300, + "h": 250, + "mtype": 3, + "ext": { + "nativery": { + "bid_ad_media_type": "UNKNOWN_TYPE", + "adv_id": "1", + "brand_category_id": 1 + } + } + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedRequestCount": 1, + "expectedMakeRequestsErrors": [], + "expectedMakeBidsErrors": [ + { + "value": "unrecognized bid_ad_media_type", + "comparison": "startswith" + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [] + } + ] +} diff --git a/adapters/nativery/nativerytest/supplemental/invalid_imp.json b/adapters/nativery/nativerytest/supplemental/invalid_imp.json new file mode 100644 index 0000000000..622ace50aa --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/invalid_imp.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "err-imp-banner-nosize", + "imp": [ + { + "id": "bad-imp-1", + "banner": {}, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { "page": "http://example.com", "ref": "http://example.com" }, + "device": { "ua": "ua", "h": 100, "w": 200 } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "err-imp-banner-nosize", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "bad-imp-1", + "banner": {}, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { "ua": "ua", "h": 100, "w": 200 } + }, + "impIDs": ["bad-imp-1"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedRequestCount": 1, + "expectedMakeRequestsErrors": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/nativery/nativerytest/supplemental/invalid_imp_ext.json b/adapters/nativery/nativerytest/supplemental/invalid_imp_ext.json new file mode 100644 index 0000000000..b55780f4fe --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/invalid_imp_ext.json @@ -0,0 +1,34 @@ +{ + "mockBidRequest": { + "id": "err-imp-ext", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": "THIS_IS_NOT_VALID_JSON" + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "ua", + "h": 100, + "w": 200 + } + }, + "expectedRequestCount": 0, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ], + "expectedMakeBidsErrors": [], + "expectedBidResponses": [] +} diff --git a/adapters/nativery/nativerytest/supplemental/invalid_response.json b/adapters/nativery/nativerytest/supplemental/invalid_response.json new file mode 100644 index 0000000000..a29d799df8 --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/invalid_response.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "err-invalid-resp", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "ua", + "h": 100, + "w": 200 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "impIDs": ["imp-1"], + "body": { + "id": "err-invalid-resp", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "ua", + "h": 100, + "w": 200 + }, + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": "NOT A JSON!" + } + } + ], + "expectedRequestCount": 1, + "expectedMakeRequestsErrors": [], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/nativery/nativerytest/supplemental/invalid_widget_id.json b/adapters/nativery/nativerytest/supplemental/invalid_widget_id.json new file mode 100644 index 0000000000..1d08bb40b6 --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/invalid_widget_id.json @@ -0,0 +1,29 @@ +{ + "mockBidRequest": { + "id": "err-nativeryext-widgetid-number", + "imp": [ + { + "id": "1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "widgetId": "1" } } + } + ], + "site": { "page": "http://example.com", "ref": "http://example.com" }, + "device": { "ua": "ua", "h": 100, "w": 200 }, + "ext": { + "nativery": { + "isAmp": false, + "widgetId": 123 + } + } + }, + "expectedRequestCount": 0, + "expectedMakeRequestsErrors": [ + { + "comparison": "regex", + "value": ".*cannot unmarshal nativery.*WidgetId.*" + } + ], + "expectedMakeBidsErrors": [], + "expectedBidResponses": [] +} diff --git a/adapters/nativery/nativerytest/supplemental/missing_widget_id.json b/adapters/nativery/nativerytest/supplemental/missing_widget_id.json new file mode 100644 index 0000000000..324cce094e --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/missing_widget_id.json @@ -0,0 +1,57 @@ +{ + "mockBidRequest": { + "id": "missing-widgetid-400", + "imp": [ + { + "id": "1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": {} } + } + ], + "site": { "page": "http://example.com", "ref": "http://example.com" }, + "device": { "ua": "ua", "h": 100, "w": 200 } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://example.com/hb", + "body": { + "id": "missing-widgetid-400", + "imp": [ + { + "id": "1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": {} } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { "ua": "ua", "h": 100, "w": 200 }, + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "" + } + } + }, + "impIDs": ["1"] + }, + "mockResponse": { + "status": 400, + "body": "" + } + } + ], + "expectedRequestCount": 1, + "expectedMakeRequestsErrors": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400", + "comparison": "startswith" + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/nativery/nativerytest/supplemental/status_204.json b/adapters/nativery/nativerytest/supplemental/status_204.json new file mode 100644 index 0000000000..f56b2832b0 --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/status_204.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {}, + "error": ["No Content"] + } + } + ], + + "expectedBidResponses": [], + + "expectedMakeBidsErrors": [ + { + "value": "No Content", + "comparison": "literal" + } + ] +} diff --git a/adapters/nativery/nativerytest/supplemental/status_204_nativery_error.json b/adapters/nativery/nativerytest/supplemental/status_204_nativery_error.json new file mode 100644 index 0000000000..8cec9dda35 --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/status_204_nativery_error.json @@ -0,0 +1,88 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {}, + "headers": { "X-Nativery-Error": ["some error"] }, + "error": ["No Content"] + } + } + ], + + "expectedBidResponses": [], + + "expectedMakeBidsErrors": [ + { "value": "Nativery Error: some error.", "comparison": "startswith" } + ] +} diff --git a/adapters/nativery/nativerytest/supplemental/status_400.json b/adapters/nativery/nativerytest/supplemental/status_400.json new file mode 100644 index 0000000000..f75a26a3eb --- /dev/null +++ b/adapters/nativery/nativerytest/supplemental/status_400.json @@ -0,0 +1,87 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/hb", + "body": { + "id": "test-request-id", + "ext": { + "nativery": { + "isAmp": false, + "widgetId": "1" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "widgetId": "1" + } + } + } + ], + "site": { + "page": "http://example.com", + "ref": "http://example.com" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", + "h": 500, + "w": 1000 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/nativery/params_test.go b/adapters/nativery/params_test.go new file mode 100644 index 0000000000..557c3e0bb9 --- /dev/null +++ b/adapters/nativery/params_test.go @@ -0,0 +1,49 @@ +package nativery + +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.BidderNativery, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected nativery 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.BidderNativery, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"widgetId":"1"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"placement_id":123}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index fa1ea996f2..af5c288967 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -163,6 +163,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/mobilefuse" "github.com/prebid/prebid-server/v3/adapters/mobkoi" "github.com/prebid/prebid-server/v3/adapters/motorik" + "github.com/prebid/prebid-server/v3/adapters/nativery" "github.com/prebid/prebid-server/v3/adapters/nativo" "github.com/prebid/prebid-server/v3/adapters/nextmillennium" "github.com/prebid/prebid-server/v3/adapters/nexx360" @@ -429,6 +430,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderMobileFuse: mobilefuse.Builder, openrtb_ext.BidderMobkoi: mobkoi.Builder, openrtb_ext.BidderMotorik: motorik.Builder, + openrtb_ext.BidderNativery: nativery.Builder, openrtb_ext.BidderNativo: nativo.Builder, openrtb_ext.BidderNextMillennium: nextmillennium.Builder, openrtb_ext.BidderNexx360: nexx360.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index c9f3fa6017..435e92eb43 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -181,6 +181,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderMobileFuse, BidderMobkoi, BidderMotorik, + BidderNativery, BidderNativo, BidderNextMillennium, BidderNexx360, @@ -551,6 +552,7 @@ const ( BidderMobileFuse BidderName = "mobilefuse" BidderMobkoi BidderName = "mobkoi" BidderMotorik BidderName = "motorik" + BidderNativery BidderName = "nativery" BidderNativo BidderName = "nativo" BidderNextMillennium BidderName = "nextmillennium" BidderNexx360 BidderName = "nexx360" diff --git a/openrtb_ext/imp_nativery.go b/openrtb_ext/imp_nativery.go new file mode 100644 index 0000000000..d63cf1e609 --- /dev/null +++ b/openrtb_ext/imp_nativery.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtNativery struct { + WidgetId string `json:"widgetId"` +} diff --git a/static/bidder-info/nativery.yaml b/static/bidder-info/nativery.yaml new file mode 100644 index 0000000000..47f05b7aaf --- /dev/null +++ b/static/bidder-info/nativery.yaml @@ -0,0 +1,12 @@ +endpoint: "https://hb.nativery.com/openrtb2/auction" +openrtb: + version: 2.6 +maintainer: + email: "developer@nativery.com" +gvlVendorID: 1133 +capabilities: + site: + mediaTypes: + - banner + - native + - video diff --git a/static/bidder-params/nativery.json b/static/bidder-params/nativery.json new file mode 100644 index 0000000000..f8d4693341 --- /dev/null +++ b/static/bidder-params/nativery.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Nativery Adapter Params", + "description": "A schema which validates params accepted by the Nativery adapter", + + "type": "object", + "properties": { + "widgetId": { + "type": "string", + "description": "An ID which identifies this Nativery widget" + } + }, + + "required": ["widgetId"] + } \ No newline at end of file From f9475e84e494f5d4300ade232f7797820f05192a Mon Sep 17 00:00:00 2001 From: Agustin Insua <Nistenf@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:37:02 -0300 Subject: [PATCH 078/272] E-Planning: Add support for adomain (#4472) --- adapters/eplanning/eplanning.go | 5 +++++ adapters/eplanning/eplanning_test.go | 3 ++- .../eplanning/eplanningtest/exemplary/simple-banner-2.json | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/adapters/eplanning/eplanning.go b/adapters/eplanning/eplanning.go index e3d3f0c1bb..fe05fee008 100644 --- a/adapters/eplanning/eplanning.go +++ b/adapters/eplanning/eplanning.go @@ -66,6 +66,7 @@ type hbResponseAd struct { Price string `json:"pr"` AdM string `json:"adm"` CrID string `json:"crid"` + Adomain string `json:"adom,omitempty"` Width uint64 `json:"w,omitempty"` Height uint64 `json:"h,omitempty"` } @@ -508,6 +509,10 @@ func (adapter *EPlanningAdapter) MakeBids(internalRequest *openrtb2.BidRequest, H: int64(ad.Height), } + if ad.Adomain != "" { + bid.ADomain = []string{ad.Adomain} + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ Bid: &bid, BidType: getBidType(impType), diff --git a/adapters/eplanning/eplanning_test.go b/adapters/eplanning/eplanning_test.go index 08af3b36b1..1d220184c6 100644 --- a/adapters/eplanning/eplanning_test.go +++ b/adapters/eplanning/eplanning_test.go @@ -1,11 +1,12 @@ package eplanning import ( + "testing" + "github.com/prebid/prebid-server/v3/adapters" "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) { diff --git a/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json b/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json index d27ca0ae9f..14ac80d2e3 100644 --- a/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json +++ b/adapters/eplanning/eplanningtest/exemplary/simple-banner-2.json @@ -43,6 +43,7 @@ "a": [{ "i": "123456789abcdef", "pr": "0.5", + "adom":"test.com", "adm": "<div>test</div>", "crid": "abcdef123456789", "id": "adid12345", @@ -65,6 +66,7 @@ "id": "123456789abcdef", "impid": "test-imp-id", "price": 0.5, + "adomain":["test.com"], "adm": "<div>test</div>", "adid": "adid12345", "crid": "abcdef123456789", From ca3daa04350cb107081a4565f3d5c7b7ae18be12 Mon Sep 17 00:00:00 2001 From: Quentin Gallard <QuentinGallard@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:47:58 +0200 Subject: [PATCH 079/272] SmileWanted: Append zoneId to endpoint path (#4468) Co-authored-by: QuentinGallard <quentin.gallard@digitalnolimit.com> --- adapters/smilewanted/smilewanted.go | 25 ++++- adapters/smilewanted/smilewanted_test.go | 58 +++++++++- .../exemplary/simple-banner.json | 6 +- .../exemplary/simple-video.json | 3 +- .../supplemental/bad-server-response.json | 6 +- .../invalid-bid-response-body.json | 55 +++++++++ .../supplemental/status-code-204.json | 6 +- .../supplemental/status-code-400.json | 6 +- .../supplemental/unexpected-status-code.json | 6 +- .../supplemental/unknown-imp-id.json | 106 ++++++++++++++++++ openrtb_ext/imp_smilewanted.go | 6 + static/bidder-info/smilewanted.yaml | 2 +- 12 files changed, 265 insertions(+), 20 deletions(-) create mode 100644 adapters/smilewanted/smilewantedtest/supplemental/invalid-bid-response-body.json create mode 100644 adapters/smilewanted/smilewantedtest/supplemental/unknown-imp-id.json create mode 100644 openrtb_ext/imp_smilewanted.go diff --git a/adapters/smilewanted/smilewanted.go b/adapters/smilewanted/smilewanted.go index 5484c8419d..3a8efdf0bb 100644 --- a/adapters/smilewanted/smilewanted.go +++ b/adapters/smilewanted/smilewanted.go @@ -18,6 +18,27 @@ type adapter struct { } func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + + // Extract zoneId from the first impression if available + var zoneId string + if len(request.Imp) > 0 { + // Parse imp.ext + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[0].Ext, &bidderExt); err == nil { + // Parse bidderExt.Bidder to get zoneId + var smilewantedExt openrtb_ext.ExtImpSmilewanted + if err := jsonutil.Unmarshal(bidderExt.Bidder, &smilewantedExt); err == nil { + zoneId = smilewantedExt.ZoneId + } + } + } + + // Build the endpoint URL with zoneId + endpoint := a.URI + if zoneId != "" { + endpoint = a.URI + zoneId + } request.AT = 1 //Defaulting to first price auction for all prebid requests @@ -36,11 +57,11 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E return []*adapters.RequestData{{ Method: "POST", - Uri: a.URI, + Uri: endpoint, Body: reqJSON, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - }}, []error{} + }}, errs } func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { diff --git a/adapters/smilewanted/smilewanted_test.go b/adapters/smilewanted/smilewanted_test.go index b63c2172e9..8e291eb505 100644 --- a/adapters/smilewanted/smilewanted_test.go +++ b/adapters/smilewanted/smilewanted_test.go @@ -1,16 +1,22 @@ package smilewanted import ( + "encoding/json" + "math" + "net/http" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" "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/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderSmileWanted, config.Adapter{ - Endpoint: "http://example.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "http://example.com/go/"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) @@ -18,3 +24,53 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "smilewantedtest", bidder) } + +// TestMakeRequestsJSONMarshalError tests the error handling when JSON marshalling fails +func TestMakeRequestsJSONMarshalError(t *testing.T) { + bidder := &adapter{ + URI: "http://example.com/go/", + } + + // Create a request with a float value that cannot be marshalled to JSON (NaN) + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{{ + ID: "test-imp-id", + BidFloor: math.NaN(), // NaN cannot be marshalled to JSON + Ext: json.RawMessage(`{"bidder": {"zoneId": "test"}}`), + }}, + } + + _, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + assert.NotNil(t, errs) + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Json not encoded") +} + +// TestMakeBidsJSONUnmarshalError tests the error handling when unmarshalling external request fails +func TestMakeBidsJSONUnmarshalError(t *testing.T) { + bidder := &adapter{ + URI: "http://example.com/go/", + } + + internalRequest := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{{ + ID: "test-imp-id", + }}, + } + + // Create external request with invalid JSON that will fail unmarshalling + externalRequest := &adapters.RequestData{ + Body: []byte(`{invalid json}`), + } + + response := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id":"test-response-id","seatbid":[{"bid":[{"id":"test-bid-id","impid":"test-imp-id","price":1.0}]}]}`), + } + + _, errs := bidder.MakeBids(internalRequest, externalRequest, response) + assert.NotNil(t, errs) + assert.Len(t, errs, 1) +} diff --git a/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json b/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json index dccf94a8eb..3a45c58544 100644 --- a/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json +++ b/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json @@ -1,10 +1,10 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", - "at" : 1, "banner": { "format": [ { @@ -25,10 +25,10 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_display", "body": { "id": "test-request-id", - "at" : 1, + "at": 1, "imp": [ { "id": "test-imp-id", diff --git a/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json b/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json index a0880bbe51..e5c07db520 100644 --- a/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json +++ b/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json @@ -1,6 +1,7 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", @@ -22,7 +23,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_video", "body": { "id": "test-request-id", "at": 1, diff --git a/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json b/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json index e6f59ab83a..155b37c00d 100644 --- a/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json +++ b/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json @@ -1,10 +1,10 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", - "at" : 1, "banner": { "format": [ { @@ -24,10 +24,10 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_display", "body": { "id": "test-request-id", - "at" : 1, + "at": 1, "imp": [ { "id": "test-imp-id", diff --git a/adapters/smilewanted/smilewantedtest/supplemental/invalid-bid-response-body.json b/adapters/smilewanted/smilewantedtest/supplemental/invalid-bid-response-body.json new file mode 100644 index 0000000000..0d6dd8b6ab --- /dev/null +++ b/adapters/smilewanted/smilewantedtest/supplemental/invalid-bid-response-body.json @@ -0,0 +1,55 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/go/testzone", + "body": { + "id": "test-request-id", + "at": 1, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "invalid json response body" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad server response: expect { or n, but found \".", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json b/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json index adc7c67006..6df0b845bf 100644 --- a/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json +++ b/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json @@ -1,10 +1,10 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", - "at" : 1, "banner": { "format": [ { @@ -25,10 +25,10 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_display", "body": { "id": "test-request-id", - "at" : 1, + "at": 1, "imp": [ { "id": "test-imp-id", diff --git a/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json b/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json index 78c6824009..d38f200615 100644 --- a/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json +++ b/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json @@ -1,10 +1,10 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", - "at" : 1, "banner": { "format": [ { @@ -25,10 +25,10 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_display", "body": { "id": "test-request-id", - "at" : 1, + "at": 1, "imp": [ { "id": "test-imp-id", diff --git a/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json b/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json index e422ca196d..07a336ace4 100644 --- a/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json +++ b/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json @@ -1,10 +1,10 @@ { "mockBidRequest": { "id": "test-request-id", + "at": 1, "imp": [ { "id": "test-imp-id", - "at" : 1, "banner": { "format": [ { @@ -25,10 +25,10 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://example.com", + "uri": "http://example.com/go/zone_code_test_display", "body": { "id": "test-request-id", - "at" : 1, + "at": 1, "imp": [ { "id": "test-imp-id", diff --git a/adapters/smilewanted/smilewantedtest/supplemental/unknown-imp-id.json b/adapters/smilewanted/smilewantedtest/supplemental/unknown-imp-id.json new file mode 100644 index 0000000000..a0c62c8169 --- /dev/null +++ b/adapters/smilewanted/smilewantedtest/supplemental/unknown-imp-id.json @@ -0,0 +1,106 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + }, + { + "id": "test-imp-2", + "video": { + "w": 640, + "h": 480, + "mimes": null + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/go/testzone", + "body": { + "id": "test-request-id", + "at": 1, + "imp": [ + { + "id": "test-imp-1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + }, + { + "id": "test-imp-2", + "video": { + "w": 640, + "h": 480, + "mimes": null + }, + "ext": { + "bidder": { + "zoneId": "testzone" + } + } + } + ] + }, + "impIDs": ["test-imp-1", "test-imp-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "unknown-imp-id", + "price": 1.0, + "adm": "<html></html>", + "crid": "creative-1" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "unknown-imp-id", + "price": 1.0, + "adm": "<html></html>", + "crid": "creative-1" + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/openrtb_ext/imp_smilewanted.go b/openrtb_ext/imp_smilewanted.go new file mode 100644 index 0000000000..1ce68ab41e --- /dev/null +++ b/openrtb_ext/imp_smilewanted.go @@ -0,0 +1,6 @@ +package openrtb_ext + +// ExtImpSmilewanted defines the contract for bidrequest.imp[i].ext.prebid.bidder.smilewanted +type ExtImpSmilewanted struct { + ZoneId string `json:"zoneId"` +} diff --git a/static/bidder-info/smilewanted.yaml b/static/bidder-info/smilewanted.yaml index e0648d417f..986fd72cf6 100644 --- a/static/bidder-info/smilewanted.yaml +++ b/static/bidder-info/smilewanted.yaml @@ -1,4 +1,4 @@ -endpoint: "https://prebid-server.smilewanted.com" +endpoint: "https://prebid-server.smilewanted.com/go/" maintainer: email: "tech@smilewanted.com" gvlVendorID: 639 From a42ab4d72341602a0ff349690dbdeaa4584e24b7 Mon Sep 17 00:00:00 2001 From: hhhjort <31041505+hhhjort@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:00:32 -0400 Subject: [PATCH 080/272] Add configurable dialer timeouts to HTTP clients (#4511) --- config/config.go | 30 +++++++++++++++++++++----- router/router.go | 56 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/config/config.go b/config/config.go index de6d04b930..d36f0e442a 100644 --- a/config/config.go +++ b/config/config.go @@ -125,11 +125,14 @@ type PriceFloorFetcher struct { const MIN_COOKIE_SIZE_BYTES = 500 type HTTPClient struct { - MaxConnsPerHost int `mapstructure:"max_connections_per_host"` - MaxIdleConns int `mapstructure:"max_idle_connections"` - MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` - IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` - Throttle HTTPThrottle `mapstructure:"throttle"` + MaxConnsPerHost int `mapstructure:"max_connections_per_host"` + MaxIdleConns int `mapstructure:"max_idle_connections"` + MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` + IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` + TLSHandshakeTimeout int `mapstructure:"tls_handshake_timeout_seconds"` + ExpectContinueTimeout int `mapstructure:"expect_continue_timeout_seconds"` + Dialer Dialer `mapstructure:"dialer"` + Throttle HTTPThrottle `mapstructure:"throttle"` } type HTTPThrottle struct { @@ -145,6 +148,11 @@ type HTTPThrottle struct { ThrottleWindow int `mapstructure:"throttle_window"` } +type Dialer struct { + TimeoutSeconds int `mapstructure:"timeout_seconds"` + KeepAliveSeconds int `mapstructure:"keep_alive_seconds"` +} + func (cfg *Configuration) validate(v *viper.Viper) []error { var errs []error errs = cfg.AuctionTimeouts.validate(errs) @@ -963,6 +971,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("http_client.max_idle_connections", 400) v.SetDefault("http_client.max_idle_connections_per_host", 10) v.SetDefault("http_client.idle_connection_timeout_seconds", 60) + v.SetDefault("http_client.tls_handshake_timeout_seconds", 10) + v.SetDefault("http_client.expect_continue_timeout_seconds", 1) + v.SetDefault("http_client.dialer.timeout_seconds", 30) + v.SetDefault("http_client.dialer.keep_alive_seconds", 15) v.SetDefault("http_client.throttle.enable_throttling", false) v.SetDefault("http_client.throttle.simulate_throttling_only", false) v.SetDefault("http_client.throttle.long_queue_wait_threshold_ms", 50) @@ -972,6 +984,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("http_client_cache.max_idle_connections", 10) v.SetDefault("http_client_cache.max_idle_connections_per_host", 2) v.SetDefault("http_client_cache.idle_connection_timeout_seconds", 60) + v.SetDefault("http_client_cache.tls_handshake_timeout_seconds", 10) + v.SetDefault("http_client_cache.expect_continue_timeout_seconds", 1) + v.SetDefault("http_client_cache.dialer.timeout_seconds", 30) + v.SetDefault("http_client_cache.dialer.keep_alive_seconds", 15) // no metrics configured by default (metrics{host|database|username|password}) v.SetDefault("metrics.disabled_metrics.account_adapter_details", false) v.SetDefault("metrics.disabled_metrics.account_debug", true) @@ -1220,6 +1236,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("price_floors.fetcher.http_client.max_idle_connections", 40) v.SetDefault("price_floors.fetcher.http_client.max_idle_connections_per_host", 2) v.SetDefault("price_floors.fetcher.http_client.idle_connection_timeout_seconds", 60) + v.SetDefault("price_floors.fetcher.http_client.tls_handshake_timeout_seconds", 10) + v.SetDefault("price_floors.fetcher.http_client.expect_continue_timeout_seconds", 1) + v.SetDefault("price_floors.fetcher.http_client.dialer.timeout_seconds", 30) + v.SetDefault("price_floors.fetcher.http_client.dialer.keep_alive_seconds", 15) v.SetDefault("price_floors.fetcher.max_retries", 10) v.SetDefault("account_defaults.events_enabled", false) diff --git a/router/router.go b/router/router.go index 9eeadaa802..3bd3ad4b79 100644 --- a/router/router.go +++ b/router/router.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "net" "net/http" "os" "strings" @@ -138,32 +139,50 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R generalHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.Client.MaxConnsPerHost, - MaxIdleConns: cfg.Client.MaxIdleConns, - MaxIdleConnsPerHost: cfg.Client.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.Client.IdleConnTimeout) * time.Second, - TLSClientConfig: &tls.Config{RootCAs: certPool}, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.Client.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.Client.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.Client.MaxConnsPerHost, + MaxIdleConns: cfg.Client.MaxIdleConns, + MaxIdleConnsPerHost: cfg.Client.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.Client.IdleConnTimeout) * time.Second, + TLSClientConfig: &tls.Config{RootCAs: certPool}, + TLSHandshakeTimeout: time.Duration(cfg.Client.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.Client.ExpectContinueTimeout) * time.Second, }, } cacheHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.CacheClient.MaxConnsPerHost, - MaxIdleConns: cfg.CacheClient.MaxIdleConns, - MaxIdleConnsPerHost: cfg.CacheClient.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.CacheClient.IdleConnTimeout) * time.Second, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.CacheClient.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.CacheClient.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.CacheClient.MaxConnsPerHost, + MaxIdleConns: cfg.CacheClient.MaxIdleConns, + MaxIdleConnsPerHost: cfg.CacheClient.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.CacheClient.IdleConnTimeout) * time.Second, + TLSHandshakeTimeout: time.Duration(cfg.CacheClient.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.CacheClient.ExpectContinueTimeout) * time.Second, }, } floorFechterHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost, - MaxIdleConns: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns, - MaxIdleConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) * time.Second, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost, + MaxIdleConns: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns, + MaxIdleConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) * time.Second, + TLSHandshakeTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.ExpectContinueTimeout) * time.Second, }, } @@ -292,6 +311,11 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R return r, nil } +// defaultTransportDialContext returns the same dialer context as the default transport uses, copied from the library code. +func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) { + return dialer.DialContext +} + // Shutdown closes any dependencies of the router that may need closing func (r *Router) Shutdown() { glog.Info("[PBS Router] shutting down") From 2df158fbacdf98ff6d5d057fb374926c6fa89571 Mon Sep 17 00:00:00 2001 From: pb360playvid <prebid@360playvid.com> Date: Tue, 23 Sep 2025 16:21:53 +0300 Subject: [PATCH 081/272] New Adapter: 360playvid (#4395) --- static/bidder-info/360playvid.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 static/bidder-info/360playvid.yaml diff --git a/static/bidder-info/360playvid.yaml b/static/bidder-info/360playvid.yaml new file mode 100644 index 0000000000..7eaacda9d2 --- /dev/null +++ b/static/bidder-info/360playvid.yaml @@ -0,0 +1,11 @@ +aliasOf: "teqblaze" +endpoint: "https://ssp.360playvid.com/pserver" +maintainer: + email: "prebid@360playvid.com" +userSync: + redirect: + url: "https://cookie.360playvid.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&coppa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://cookie.360playvid.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file From b415ca49e5c6567131186fc3aecd75c802ed5c70 Mon Sep 17 00:00:00 2001 From: mediayo <yehuda@mediayo.co> Date: Tue, 23 Sep 2025 16:47:08 +0300 Subject: [PATCH 082/272] New Adapter: MediaYo (#4391) --- static/bidder-info/mediayo.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/mediayo.yaml diff --git a/static/bidder-info/mediayo.yaml b/static/bidder-info/mediayo.yaml new file mode 100644 index 0000000000..0730b834a9 --- /dev/null +++ b/static/bidder-info/mediayo.yaml @@ -0,0 +1,4 @@ +aliasOf: 'teqblaze' +endpoint: "https://balancer.mediayo.ai/pserver" +maintainer: + email: "admin@mediayo.co" From a9343109d8524ffe0eb0e85d6dfc96fa93002db5 Mon Sep 17 00:00:00 2001 From: Carlos Felix <carloshto@gmail.com> Date: Tue, 23 Sep 2025 07:58:58 -0600 Subject: [PATCH 083/272] 33across: Make zoneId the preferred option (#4531) --- adapters/33across/params_test.go | 10 +++++++--- openrtb_ext/imp_33across.go | 2 +- static/bidder-params/33across.json | 5 ++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/adapters/33across/params_test.go b/adapters/33across/params_test.go index 3169a1d994..8517c5939a 100644 --- a/adapters/33across/params_test.go +++ b/adapters/33across/params_test.go @@ -40,15 +40,19 @@ func TestInvalidParams(t *testing.T) { } var validParams = []string{ + `{"productId": "inview", "zoneId": "zone1"}`, + `{"productId": "siab", "zoneId": "fakezoneid2"}`, + `{"productId": "inview", "zoneId": "zone1", "siteId": "foo.ba"}`, `{"productId": "inview", "siteId": "fakesiteid1"}`, - `{"productId": "siab", "siteId": "fakesiteid2"}`, - `{"productId": "inview", "siteId": "foo.ba", "zoneId": "zone1"}`, } var invalidParams = []string{ `{"productId": "inview"}`, + `{"zoneId": "fakezoneid2"}`, `{"siteId": "fakesiteid2"}`, + `{"productId": 123, "zoneId": "fakesiteid2"}`, `{"productId": 123, "siteId": "fakesiteid2"}`, + `{"productId": "siab", "zoneId": 123}`, `{"productId": "siab", "siteId": 123}`, - `{"productId": "siab", "siteId": "fakesiteid2", "zoneId": 123}`, + `{"productId": "siab", "zoneId": 123, "siteId": "fakesiteid2"}`, } diff --git a/openrtb_ext/imp_33across.go b/openrtb_ext/imp_33across.go index 3a46fab497..58e1e608c6 100644 --- a/openrtb_ext/imp_33across.go +++ b/openrtb_ext/imp_33across.go @@ -2,7 +2,7 @@ package openrtb_ext // ExtImp33across defines the contract for bidrequest.imp[i].ext.prebid.bidder.33across type ExtImp33across struct { - SiteId string `json:"siteId"` ZoneId string `json:"zoneId,omitempty"` + SiteId string `json:"siteId,omitempty"` ProductId string `json:"productId,omitempty"` } diff --git a/static/bidder-params/33across.json b/static/bidder-params/33across.json index b535121574..190d92f73e 100644 --- a/static/bidder-params/33across.json +++ b/static/bidder-params/33across.json @@ -19,5 +19,8 @@ "description": "Zone Id" } }, - "required": ["productId", "siteId"] + "anyOf": [ + { "required": ["productId", "siteId"] }, + { "required": ["productId", "zoneId"] } + ] } \ No newline at end of file From a9bbbcd4e937224a77b8417b6ca0e0bf988d3a8d Mon Sep 17 00:00:00 2001 From: Carlos Felix <carloshto@gmail.com> Date: Tue, 23 Sep 2025 08:11:25 -0600 Subject: [PATCH 084/272] 33across: Remove deprecated video.placement (#4530) --- adapters/33across/33across.go | 6 ------ .../33acrosstest/exemplary/bidresponse-defaults.json | 8 ++++---- .../33acrosstest/exemplary/instream-video-defaults.json | 5 ++--- .../33across/33acrosstest/exemplary/multi-format.json | 5 ++--- .../33acrosstest/exemplary/outstream-video-defaults.json | 5 ++--- adapters/33across/33acrosstest/exemplary/site-video.json | 8 ++++---- 6 files changed, 14 insertions(+), 23 deletions(-) diff --git a/adapters/33across/33across.go b/adapters/33across/33across.go index 94ddf1f91f..45a7ea3656 100644 --- a/adapters/33across/33across.go +++ b/adapters/33across/33across.go @@ -256,13 +256,7 @@ func validateVideoParams(video *openrtb2.Video, prod string) (*openrtb2.Video, e } } - if videoCopy.Placement == 0 { - videoCopy.Placement = 2 - } - if prod == "instream" { - videoCopy.Placement = 1 - if videoCopy.StartDelay == nil { videoCopy.StartDelay = adcom1.StartDelay.Ptr(0) } diff --git a/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json b/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json index 9f6a28e6d1..185b7298dd 100644 --- a/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json @@ -5,10 +5,10 @@ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 1, + "plcmt": 1, "startdelay": -2, "playbackmethod": [2], "mimes": ["foo", "bar"] @@ -44,10 +44,10 @@ { "id":"test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 1, + "plcmt": 1, "startdelay": -2, "playbackmethod": [2], "mimes": ["foo", "bar"] diff --git a/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json b/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json index 9b7c717153..52df58e8b6 100644 --- a/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json @@ -5,7 +5,7 @@ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], "playbackmethod": [2], @@ -42,10 +42,9 @@ { "id":"test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 1, "startdelay": 0, "playbackmethod": [2], "mimes": ["foo", "bar"] diff --git a/adapters/33across/33acrosstest/exemplary/multi-format.json b/adapters/33across/33acrosstest/exemplary/multi-format.json index af09bb75cb..f07ca06f0a 100644 --- a/adapters/33across/33acrosstest/exemplary/multi-format.json +++ b/adapters/33across/33acrosstest/exemplary/multi-format.json @@ -8,7 +8,7 @@ "format": [{"w": 728, "h": 90}] }, "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], "playbackmethod": [2], @@ -48,10 +48,9 @@ "format": [{"w": 728, "h": 90}] }, "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 2, "playbackmethod": [2], "mimes": ["foo", "bar"] }, diff --git a/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json b/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json index 7044a145a7..ecfb42cf11 100644 --- a/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json @@ -5,7 +5,7 @@ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], "playbackmethod": [2], @@ -42,10 +42,9 @@ { "id":"test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 2, "playbackmethod": [2], "mimes": ["foo", "bar"] }, diff --git a/adapters/33across/33acrosstest/exemplary/site-video.json b/adapters/33across/33acrosstest/exemplary/site-video.json index 12170cb77d..5905aaca90 100644 --- a/adapters/33across/33acrosstest/exemplary/site-video.json +++ b/adapters/33across/33acrosstest/exemplary/site-video.json @@ -5,10 +5,10 @@ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 1, + "plcmt": 1, "startdelay": -2, "playbackmethod": [2], "mimes": ["foo", "bar"] @@ -44,10 +44,10 @@ { "id":"test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, "protocols": [2], - "placement": 1, + "plcmt": 1, "startdelay": -2, "playbackmethod": [2], "mimes": ["foo", "bar"] From 13c49224de99472142b5e6bd42b1e0d9192f0fe9 Mon Sep 17 00:00:00 2001 From: rbstdev <devgit204@gmail.com> Date: Tue, 23 Sep 2025 17:34:32 +0300 Subject: [PATCH 085/272] New Adapter: RobustApps - Xeworks alias (#4434) Co-authored-by: And-Rud <andrii@xe.works> Co-authored-by: rbstdev <devgit204@xe.works> --- static/bidder-info/robustApps.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/robustApps.yaml diff --git a/static/bidder-info/robustApps.yaml b/static/bidder-info/robustApps.yaml new file mode 100644 index 0000000000..fc0aeada86 --- /dev/null +++ b/static/bidder-info/robustApps.yaml @@ -0,0 +1,9 @@ +aliasOf: "xeworks" +endpoint: "http://rtb.rbstsystems.live?pid={{.SourceId}}&host={{.Host}}&pbs=1" +maintainer: + email: "prebid@robust-apps.com" +userSync: + # robustApps supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - redirect From 4a73cf793da5f6f4a6b55a3de98010b0bde832be Mon Sep 17 00:00:00 2001 From: GodefroiRoussel <GodefroiRoussel@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:49:46 +0200 Subject: [PATCH 086/272] Adagio: Remove max length on params (#4524) Co-authored-by: Godefroi Roussel <groussel@adagio.io> --- adapters/adagio/params_test.go | 4 ---- static/bidder-params/adagio.json | 17 ++++++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/adapters/adagio/params_test.go b/adapters/adagio/params_test.go index c0c09a2734..e7619b5298 100644 --- a/adapters/adagio/params_test.go +++ b/adapters/adagio/params_test.go @@ -59,12 +59,8 @@ var invalidParams = []string{ `{"site":"mywebsite-com"}`, `{"organizationId":1000}`, `{"organizationId":1000,"placement":"some-placement"}`, - `{"organizationId":"1000","placement":"this-is-a-very-very-long-placement"}`, `{"organizationId":"1000","placement":123456}`, `{"organizationId":"1000","placement":"some-placement","pagetype":123456}`, - `{"organizationId":"1000","placement":"some-placement","pagetype":"this-is-a-very-very-long-pagetype"}`, `{"organizationId":"1000","placement":"some-placement","category":123456}`, - `{"organizationId":"1000","placement":"some-placement","category":"this-is-a-very-very-long-category"}`, `{"organizationId":"1000","placement":"some-placement","site":123456}`, - `{"organizationId":"1000","placement":"some-placement","site":"this-is-a-very-very-very-very-very-very-long-site-name"}`, } diff --git a/static/bidder-params/adagio.json b/static/bidder-params/adagio.json index 4be32a3592..709ca1a967 100644 --- a/static/bidder-params/adagio.json +++ b/static/bidder-params/adagio.json @@ -10,24 +10,23 @@ }, "placement": { "type": "string", - "description": "Refers to the placement of an adunit in a page. Must not contain any information about the type of device.", - "maxLength": 30 + "description": "Refers to the placement of an adunit in a page. Must not contain any information about the type of device." }, "site": { "type": "string", - "description": "Name of the site. Handed out by Adagio.", - "maxLength": 50 + "description": "Name of the site. Handed out by Adagio." }, "pagetype": { "type": "string", - "description": "Describes what kind of content will be present in the page.", - "maxLength": 30 + "description": "Describes what kind of content will be present in the page." }, "category": { "type": "string", - "description": "Category of the content displayed in the page.", - "maxLength": 30 + "description": "Category of the content displayed in the page." } }, - "required": ["organizationId", "placement"] + "required": [ + "organizationId", + "placement" + ] } \ No newline at end of file From e59241ec9b3de684bb1255ae8c85fddbc9bb0765 Mon Sep 17 00:00:00 2001 From: Wenyuan Zhang <wzhang910@cable.comcast.com> Date: Tue, 23 Sep 2025 11:26:37 -0400 Subject: [PATCH 087/272] fwssp: Add iframe usersync (#4487) Co-authored-by: wenyuanzhang <wenyuanzhang@freewheel.tv> --- static/bidder-info/fwssp.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/bidder-info/fwssp.yaml b/static/bidder-info/fwssp.yaml index e06754d037..e453684d09 100644 --- a/static/bidder-info/fwssp.yaml +++ b/static/bidder-info/fwssp.yaml @@ -13,3 +13,7 @@ capabilities: site: mediaTypes: - video +userSync: + iframe: + url: "https://user-sync.fwmrm.net/ad/u?mode=pbs-user-sync&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&pbs_redirect={{.RedirectURL}}" + userMacro: "#{user.id}" \ No newline at end of file From 066bbe708cdb8f503bd3d74666e11fa8c38c81a2 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley <bokelley@scope3.com> Date: Tue, 23 Sep 2025 17:46:51 +0200 Subject: [PATCH 088/272] Module: Scope3 Real-Time Data (#4397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Scope3 Real-Time Data (RTD) module This module integrates Scope3's Real-Time Data API to provide audience segments for targeting in Prebid Server auctions. Features: - Fetches real-time audience segments from Scope3 API - Adds targeting data to bid requests via hooks system - Thread-safe segment storage during auction lifecycle - Configurable timeout and endpoint settings - Graceful error handling that doesn't fail auctions The module implements three hook stages: - Entrypoint: Initialize module context - Raw Auction Request: Fetch segments from Scope3 API - Processed Auction Request: Add segments to targeting data 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Add LiveRamp ATS integration and execution order documentation - Document proper execution order when using with LiveRamp ATS - Add user identifier detection for RampID integration - Include configuration examples for sequential module execution - Enhance API requests with available user identifiers - Add comprehensive documentation for Yahoo deployment scenario 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Add LiveRamp ATS envelope support for publishers without sidecar - Support forwarding encrypted ATS envelopes directly to Scope3 API - Check multiple envelope locations: user.ext.liveramp_idl, user.ext.ats_envelope, ext.liveramp_idl - Prioritize sidecar RampID over envelope when both available - Document both sidecar and envelope integration patterns - Add note about Scope3 needing LiveRamp partner authorization This enables publishers without LiveRamp sidecar to still benefit from LiveRamp ATS user signals via encrypted envelope forwarding. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Clean up debug code and finalize production-ready Scope3 RTD module - Remove all debug logging statements - Streamline segment storage and retrieval between hooks - Finalize request-level targeting for GAM integration - Production-ready code with proper error handling - Complete documentation with configuration examples The module is now ready for production deployment with: - Successful Scope3 API integration - LiveRamp ATS compatibility (sidecar and envelope) - GAM targeting data output - Thread-safe segment management 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Simplify targeting output to single GAM-compatible format - Remove duplicate data.scope3_segments array format - Keep only targeting.hb_scope3_segments as comma-separated string - Follows standard header bidding targeting key conventions - Optimized for GAM key-value targeting integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Add unit tests for Scope3 RTD module - Add basic unit tests for module builder and hook functions - Test invalid config handling and error cases - Test entrypoint hook initialization - Test processed auction hook with no segments - Satisfy CI requirements for test coverage 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix Go formatting issues - Remove trailing whitespace in module.go - Add missing newline at end of module_test.go - Satisfy gofmt validation requirements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Address PR feedback: Add caching, improve LiveRamp integration, enhance configurability Key improvements based on reviewer feedback: - Add intelligent caching with configurable TTL to handle repeated requests - Set 60-second default cache TTL for frequency cap compatibility - Improve LiveRamp identifier detection across multiple locations - Remove unsubstantiated partnership claims and improve documentation - Add cache_ttl_seconds and bid_meta_data configuration options - Implement MD5-based cache keys from user IDs and site context - Add comprehensive test coverage for new caching functionality - Update documentation to explain targeting vs bid.meta approach - Change default timeout to 1000ms for better API compatibility Addresses concerns about: - Performance with hundreds of identical requests per user session - Flexibility in targeting data output (bid.meta future enhancement noted) - Accurate LiveRamp integration documentation - Proper hook implementation code naming 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Complete PR feedback implementation: Response-level segments with GAM targeting Major changes to address all PR reviewer feedback: **Response Format Changes:** - Move from request targeting to auction response data per reviewer feedback - Change hook stage from processed_auction_request to auction_response - Add segments to response.ext.scope3.segments for publisher control - Add individual GAM targeting keys when add_to_targeting=true (e.g., gmp_eligible=true) **Configuration Updates:** - Rename bid_meta_data to add_to_targeting for clarity - Add comprehensive GAM integration with individual segment keys - Remove incorrect LiveRamp RTD adapter references from README - Update hook configuration examples to use auction_response stage **API Integration Fixes:** - Correct segment parsing to exclude destination field (triplelift.com) - Extract only actual segments from imp[].ext.scope3.segments[] - Maintain working authentication and caching functionality **Enhanced Testing:** - Add comprehensive mock API integration tests - Test both response formats (scope3 + targeting sections) - Test error handling with mock server responses - Apply gofmt formatting to all code **Publisher Benefits:** - Full control over segment usage via response.ext.scope3.segments - Optional automated GAM integration via individual targeting keys - Flexible configuration for different use cases - Maintains caching for high-frequency scenarios Addresses all PR reviewer concerns while providing maximum publisher flexibility. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Address PR feedback: Add optimized HTTP Transport for high-frequency API calls Per reviewer feedback (@gravelg): 'if we're going to be make a lot of calls, we should use a Transport with better defaults' - MaxIdleConns: 100 (increased connection pool) - MaxIdleConnsPerHost: 10 (multiple connections per host) - IdleConnTimeout: 90s (longer connection reuse) - ForceAttemptHTTP2: true (HTTP/2 for better performance) - DisableCompression: false (bandwidth optimization) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * run gofmt * update default endpoint * fix test * address comments * more review comments * address more comments * remove unused enhanceRequestWithUserIDs method * jsonutil, add more tests * Add privacy field masking for Scope3 RTD module Implement comprehensive privacy protection by masking sensitive user data before sending bid requests to the Scope3 API while preserving essential targeting capabilities. Features: - Configurable field masking with privacy-first defaults - Geographic data truncation with configurable precision (default: 2 decimals ~1.1km) - Identity provider filtering with allowlist for preserved EIDs - Always removes: IP addresses, user IDs, demographics, first-party data - Always preserves: device characteristics, country/region, site/app context - Comprehensive test coverage (92.3%) with edge case handling - All linting checks pass with zero issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix cache key generation for proper per-user caching - Use SHA-256 hashed user.id as fallback when privacy-safe identifiers are unavailable - Maintains per-user cache segmentation for performance while protecting privacy - Privacy-safe identifiers (RampID, LiverampIDL) take priority over hashed user.id - Prevents accidental data leakage by returning nil on masking failures - Add configuration validation for geo precision (max 4 decimal places) - Add comprehensive tests for cache key behavior and configuration validation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix gofmt formatting in module_test.go 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * review fixes * more review comments * make it async * address more comments --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Gabriel Gravel <ggravel@scope3.com> --- modules/builder.go | 4 + modules/scope3/rtd/README.md | 349 +++++++ modules/scope3/rtd/async_request.go | 53 + modules/scope3/rtd/masking.go | 200 ++++ modules/scope3/rtd/module.go | 484 +++++++++ modules/scope3/rtd/module_test.go | 1427 +++++++++++++++++++++++++++ 6 files changed, 2517 insertions(+) create mode 100644 modules/scope3/rtd/README.md create mode 100644 modules/scope3/rtd/async_request.go create mode 100644 modules/scope3/rtd/masking.go create mode 100644 modules/scope3/rtd/module.go create mode 100644 modules/scope3/rtd/module_test.go diff --git a/modules/builder.go b/modules/builder.go index eef0bd5992..85a38fd022 100644 --- a/modules/builder.go +++ b/modules/builder.go @@ -4,6 +4,7 @@ import ( fiftyonedegreesDevicedetection "github.com/prebid/prebid-server/v3/modules/fiftyonedegrees/devicedetection" prebidOrtb2blocking "github.com/prebid/prebid-server/v3/modules/prebid/ortb2blocking" prebidRulesengine "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine" + scope3Rtd "github.com/prebid/prebid-server/v3/modules/scope3/rtd" ) // builders returns mapping between module name and its builder @@ -17,5 +18,8 @@ func builders() ModuleBuilders { "ortb2blocking": prebidOrtb2blocking.Builder, "rulesengine": prebidRulesengine.Builder, }, + "scope3": { + "rtd": scope3Rtd.Builder, + }, } } diff --git a/modules/scope3/rtd/README.md b/modules/scope3/rtd/README.md new file mode 100644 index 0000000000..734874b0bc --- /dev/null +++ b/modules/scope3/rtd/README.md @@ -0,0 +1,349 @@ +# Scope3 RTD Module + +This module integrates Scope3's Real-Time Data API to provide audience segments for targeting. + +## Maintainer +- Email: bokelley@scope3.com +- Company: Scope3 + +## Configuration + +### YAML Configuration +```yaml +hooks: + enabled: true + modules: + scope3: + rtd: + enabled: true + auth_key: ${SCOPE3_API_KEY} # Set SCOPE3_API_KEY environment variable + endpoint: https://rtdp.scope3.com/amazonaps/rtii + timeout_ms: 1000 + cache_ttl_seconds: 60 # Cache segments for 60 seconds (default) + add_to_targeting: false # Set to true to add segments as individual targeting keys for GAM + masking: # Optional privacy masking configuration + enabled: true # Enable field masking before sending to Scope3 + geo: + preserve_metro: true # Preserve DMA code (default: true) + preserve_zip: true # Preserve postal code (default: true) + preserve_city: false # Preserve city name (default: false) + lat_long_precision: 2 # Lat/long decimal places: 0-4 (default: 2) + user: + preserve_eids: # EID sources to preserve (default list below) + - "liveramp.com" # RampID + - "uidapi.com" # UID2 + - "id5-sync.com" # ID5 + device: + preserve_mobile_ids: false # Keep mobile advertising IDs (default: false) + + host_execution_plan: + endpoints: + /openrtb2/auction: + stages: + entrypoint: + groups: + - timeout: 5 + hook_sequence: + - module_code: "scope3.rtd" + hook_impl_code: "HandleEntrypointHook" + raw_auction_request: + groups: + - timeout: 2000 + hook_sequence: + - module_code: "scope3.rtd" + hook_impl_code: "HandleRawAuctionHook" + auction_response: + groups: + - timeout: 5 + hook_sequence: + - module_code: "scope3.rtd" + hook_impl_code: "HandleAuctionResponseHook" +``` + +### JSON Configuration +```json +{ + "hooks": { + "modules": { + "scope3": { + "rtd": { + "enabled": true, + "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "auth_key": "your-scope3-auth-key", + "timeout_ms": 1000, + "cache_ttl_seconds": 60, + "add_to_targeting": false, + "masking": { + "enabled": true, + "geo": { + "preserve_metro": true, + "preserve_zip": true, + "preserve_city": false, + "lat_long_precision": 2 + }, + "user": { + "preserve_eids": ["liveramp.com", "uidapi.com", "id5-sync.com"] + }, + "device": { + "preserve_mobile_ids": false + } + } + } + } + } + } +} +``` + +## Environment Variables +- `SCOPE3_API_KEY`: Your Scope3 API key for authentication + +## Privacy Protection + +This module includes comprehensive privacy masking to protect user data while preserving targeting capabilities. When masking is enabled, sensitive user information is removed or anonymized before being sent to the Scope3 API. + +### Field Masking Categories + +#### 🟢 ALWAYS SENT (Never Masked) +These fields are always passed through without modification as they are not considered sensitive: + +**Device Information** +- `device.devicetype` - Device type (mobile, desktop, CTV, etc.) +- `device.os` - Operating system +- `device.osv` - OS version +- `device.make` - Device manufacturer +- `device.model` - Device model +- `device.ua` - User agent string +- `device.language` - Language preference +- `device.connectiontype` - Connection type (wifi, cellular, etc.) +- `device.js` - JavaScript support +- `device.h/w` - Screen dimensions +- `device.ppi` - Screen PPI +- `device.pxratio` - Pixel ratio + +**Geographic Information (Coarse)** +- `geo.country` - Country code (e.g., "US") +- `geo.region` - State/region code (e.g., "CA") + +**Context Information** +- `site.*` - All site fields (domain, page, ref, etc.) +- `app.*` - All app fields +- `imp.*` - All impression data (ad sizes, positions, etc.) + +#### 🔴 NEVER SENT (Always Masked) +These fields are always removed for privacy protection: + +**Personal Identifiers** +- `device.ip` - IPv4 address +- `device.ipv6` - IPv6 address +- `user.id` - Publisher's first-party user ID +- `user.buyeruid` - Exchange-specific user ID +- `user.yob` - Year of birth +- `user.gender` - Gender +- `user.data` - First-party data segments +- `user.keywords` - User interest keywords + +**High-Precision Location** +- `geo.accuracy` - GPS accuracy radius + +#### 🔧 CONFIGURABLE (With Defaults) +These fields can be configured to be preserved or masked: + +**Geographic Information (Fine-Grained)** + +| Field | Default | Options | Privacy Impact | +|-------|---------|---------|----------------| +| `geo.metro` | **Preserved** | preserve/remove | DMA code for regional targeting | +| `geo.zip` | **Preserved** | preserve/remove | Postal code for local targeting | +| `geo.city` | **Removed** | preserve/remove | City name | +| `geo.lat/lon` | **Truncated to 2 decimals** | 0-4 decimals or remove | See precision guide below | + +**User Identifiers** + +| Field | Default | Options | Notes | +|-------|---------|---------|-------| +| `user.eids` | **Filter to allowlist** | List of EID sources | Default: ["liveramp.com", "uidapi.com", "id5-sync.com"] | + +**Device Identifiers** + +| Field | Default | Options | Notes | +|-------|---------|---------|-------| +| `device.ifa` | **Removed** | preserve/remove | Mobile advertising ID | +| `device.dpidmd5` | **Removed** | preserve/remove | Hashed device ID | +| `device.dpidsha1` | **Removed** | preserve/remove | Hashed device ID | +| Other device IDs | **Removed** | preserve/remove | Various hashed identifiers | + +### Geographic Precision Guide + +When preserving latitude/longitude coordinates, the precision level has significant privacy implications: + +| Decimals | Accuracy | Privacy Level | Use Case | +|----------|----------|---------------|----------| +| 0 | Removed | Maximum | No location data | +| 1 | ~11 km | Country/State | Regional campaigns | +| 2 | ~1.1 km | **Neighborhood (Default)** | Store radius matching | +| 3 | ~111 m | City block | Dense urban targeting | +| 4 | ~11 m | Building | Maximum allowed | + +⚠️ **WARNING**: More than 4 decimal places can identify individuals and is not permitted by this module. + +### Configuration Examples + +#### Maximum Privacy (Strict Mode) +```yaml +masking: + enabled: true + geo: + preserve_metro: false + preserve_zip: false + preserve_city: false + lat_long_precision: 0 + user: + preserve_eids: [] + device: + preserve_mobile_ids: false +``` + +#### Balanced Privacy (Default) +```yaml +masking: + enabled: true + geo: + preserve_metro: true + preserve_zip: true + preserve_city: false + lat_long_precision: 2 + user: + preserve_eids: ["liveramp.com", "uidapi.com", "id5-sync.com"] + device: + preserve_mobile_ids: false +``` + +#### Retail/Commerce Optimization +```yaml +masking: + enabled: true + geo: + preserve_metro: true + preserve_zip: true + preserve_city: true + lat_long_precision: 3 # Higher precision for store matching + user: + preserve_eids: ["liveramp.com", "retail-partner.com"] + device: + preserve_mobile_ids: true # For in-store attribution +``` + +### Privacy Compliance + +**GDPR Compliance** +- Removes direct identifiers by default +- Configurable to meet legitimate interest requirements +- Supports privacy-by-design principles + +**CCPA Compliance** +- Removes sale-related identifiers +- Supports consumer privacy rights +- Configurable per jurisdiction requirements + +**Industry Standards** +- Follows IAB OpenRTB privacy guidelines +- Compatible with TCF 2.0 consent frameworks +- Supports Privacy Sandbox initiatives + +## Features +- **Privacy-First Design**: Comprehensive field masking to protect user data while preserving targeting +- **Flexible Masking**: Configurable privacy controls for different use cases and compliance requirements +- **Real-Time Segments**: Fetches audience segments from Scope3 API with intelligent caching +- **Thread-Safe Caching**: Handles high-frequency requests with concurrent access protection +- **Identity Integration**: Supports multiple identity providers (LiveRamp, UID2, ID5, etc.) +- **Geographic Privacy**: Truncates location data to configurable precision levels +- **Graceful Degradation**: Continues auction processing even when API errors occur +- **Performance Optimized**: HTTP/2, connection pooling, and compression for high-traffic scenarios + +## Performance & Caching +This module implements intelligent caching and HTTP optimizations to handle high-frequency API requests: + +- **Cache Key**: Generated from user identifiers, site domain, and page URL +- **Cache Duration**: Configurable via `cache_ttl_seconds` (default: 60 seconds) +- **Thread Safety**: Uses read-write mutexes for concurrent access +- **Memory Efficiency**: Stores only segment arrays, not full API responses +- **Frequency Cap Compatibility**: Short 60-second default ensures frequency-capped segments are refreshed quickly +- **HTTP Optimization**: Custom transport with connection pooling, HTTP/2, and compression for better performance + +## User Identity Integration +This module automatically detects and forwards available user identifiers from the bid request including: + +- LiveRamp identifiers (when available from publisher implementations or identity providers) +- Publisher first-party user IDs +- Device identifiers +- Encrypted identity envelopes + + +### Supported Identifier Types +1. **LiveRamp Identifiers** (when available): + - `user.ext.eids[]` array with `source: "liveramp.com"` + - `user.ext.rampid` field (alternative location) + +2. **Encrypted Identity Envelopes**: + - `user.ext.liveramp_idl` - ATS envelope location + - `user.ext.ats_envelope` - Alternative envelope location + - `user.ext.rampId_envelope` - Additional envelope location + - `ext.liveramp_idl` - Request-level envelope + +3. **Standard Identifiers**: + - `user.id` - Publisher user ID + - `device.ifa` - Device identifier + - Other standard OpenRTB identifiers + +### How It Works +The module forwards the complete bid request with all available user identifiers to the Scope3 API. Scope3's system can then utilize whatever identifiers are available for audience segmentation, whether they are resolved identifiers or encrypted envelopes that Scope3 may be able to process. + +**Note**: The effectiveness of different identifier types depends on Scope3's integration capabilities and partnerships. + +## Data Output & Integration + +### Auction Response Data +The module adds audience segments to the auction response, giving publishers full control over how to use them: + +1. **Publisher Flexibility**: Segments are always returned in `ext.scope3.segments` for the publisher to decide where to send +2. **Google Ad Manager (GAM)**: Individual targeting keys are added when `add_to_targeting: true` (e.g., `gmp_eligible=true`) +3. **Other Ad Servers**: Publisher can forward segments to any ad server or system +4. **Analytics**: Segment data is available for reporting and analysis + +### Response Format Options +The module provides segments in two formats: + +**Always available:** +```json +{ + "ext": { + "scope3": { + "segments": ["gmp_eligible", "gmp_plus_eligible"] + } + } +} +``` + +**When `add_to_targeting: true`:** +```json +{ + "ext": { + "prebid": { + "targeting": { + "gmp_eligible": "true", + "gmp_plus_eligible": "true" + } + }, + "scope3": { + "segments": ["gmp_eligible", "gmp_plus_eligible"] + } + } +} +``` + +This approach gives publishers maximum flexibility to: +- Send segments to GAM via targeting keys +- Forward to other ad servers or systems +- Use for analytics and reporting +- Control which segments go where based on their business logic diff --git a/modules/scope3/rtd/async_request.go b/modules/scope3/rtd/async_request.go new file mode 100644 index 0000000000..38c4663286 --- /dev/null +++ b/modules/scope3/rtd/async_request.go @@ -0,0 +1,53 @@ +package scope3 + +import ( + "context" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" +) + +type ( + AsyncRequest struct { + *Module + + // For managing the lifecycle of the request + // Context is used to pass to the request. This should be the context of the original request + Context context.Context + // Cancel can be called to cancel the request + Cancel context.CancelFunc + // DoneChannel will be closed when the request is done. When nil, no request was made + Done chan struct{} + + // Response + Segments []string + Err error + } +) + +// NewAsyncRequest creates a new AsyncRequest object +// The request's context is used to create a cancellable context for the async request and, which spans multiple hooks +func (m *Module) NewAsyncRequest(req *http.Request) *AsyncRequest { + ret := &AsyncRequest{ + Module: m, + } + ret.Context, ret.Cancel = context.WithCancel(req.Context()) + return ret +} + +// fetchScope3SegmentsAsync starts a goroutine to fetch Scope3 segments and immediately returns +// The Done channel will be closed when the request is done +// If the Done channel is nil, no request was made +func (ar *AsyncRequest) fetchScope3SegmentsAsync(request *openrtb2.BidRequest) { + ar.Done = make(chan struct{}) + go func() { + defer func() { + if r := recover(); r != nil { + ar.Err = fmt.Errorf("panic in async request: %v", r) + } + close(ar.Done) + }() + ar.Segments, ar.Err = ar.Module.fetchScope3Segments(ar.Context, request) + }() +} diff --git a/modules/scope3/rtd/masking.go b/modules/scope3/rtd/masking.go new file mode 100644 index 0000000000..d32689dacf --- /dev/null +++ b/modules/scope3/rtd/masking.go @@ -0,0 +1,200 @@ +package scope3 + +import ( + "math" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/util/iterutil" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +// maskBidRequest creates a deep copy of the bid request with sensitive fields masked +// according to the masking configuration. Returns nil if masking fails to prevent +// accidental exposure of sensitive data. +func (m *Module) maskBidRequest(original *openrtb2.BidRequest) *openrtb2.BidRequest { + if !m.cfg.Masking.Enabled { + return original + } + + // Create a deep copy by marshaling and unmarshaling + data, err := jsonutil.Marshal(original) + if err != nil { + // Never return unmasked data - this prevents potential data leakage + // The calling function should handle nil gracefully + return nil + } + + var masked openrtb2.BidRequest + if err := jsonutil.Unmarshal(data, &masked); err != nil { + // Never return unmasked data - this prevents potential data leakage + // The calling function should handle nil gracefully + return nil + } + + // Apply masking to different sections + m.maskUser(&masked) + m.maskDevice(&masked) + m.maskGeo(&masked) + + return &masked +} + +// maskUser removes or filters user data according to privacy settings +func (m *Module) maskUser(req *openrtb2.BidRequest) { + if req.User == nil { + return + } + + // Always remove publisher's first-party user ID for privacy + req.User.ID = "" + req.User.BuyerUID = "" + + // Always remove potentially sensitive demographic data + req.User.Yob = 0 + req.User.Gender = "" + + // Remove user data segments (first-party data) + req.User.Data = nil + req.User.Keywords = "" + + // Filter user.eids to only preserve allowed identity providers + req.User.EIDs = m.filterEids(req.User.EIDs) +} + +// filterEids filters the user.eids array to only include allowed identity providers +func (m *Module) filterEids(eids []openrtb2.EID) []openrtb2.EID { + if len(m.cfg.Masking.User.PreserveEids) == 0 { + return []openrtb2.EID{} + } + + // Create allowlist map for fast lookup + allowed := make(map[string]bool) + for _, source := range m.cfg.Masking.User.PreserveEids { + allowed[source] = true + } + + // Filter eids to only include allowed sources + var filtered []openrtb2.EID + for eid := range iterutil.SlicePointerValues(eids) { + if allowed[eid.Source] { + // Intentionally copy the EID struct to create a new filtered slice + // that's independent of the original data + filtered = append(filtered, *eid) + } + } + + return filtered +} + +// maskDevice removes sensitive device information while preserving targeting-safe data +func (m *Module) maskDevice(req *openrtb2.BidRequest) { + if req.Device == nil { + return + } + + // Always remove IP addresses for privacy + req.Device.IP = "" + req.Device.IPv6 = "" + + // Remove mobile advertising IDs unless explicitly preserved + if !m.cfg.Masking.Device.PreserveMobileIds { + req.Device.IFA = "" + req.Device.DPIDMD5 = "" + req.Device.DPIDSHA1 = "" + req.Device.DIDMD5 = "" + req.Device.DIDSHA1 = "" + req.Device.MACMD5 = "" + req.Device.MACSHA1 = "" + } + + // Note: We preserve device characteristics like devicetype, os, browser, etc. + // as these are not considered personally identifiable and are useful for targeting +} + +// maskGeo removes or truncates geographic data according to privacy settings +func (m *Module) maskGeo(req *openrtb2.BidRequest) { + // Mask device geo + if req.Device != nil && req.Device.Geo != nil { + m.maskGeoObject(req.Device.Geo) + } + + // Mask user geo (if different from device geo) + if req.User != nil && req.User.Geo != nil { + m.maskGeoObject(req.User.Geo) + } +} + +// maskGeoObject applies geographic masking rules to a geo object +func (m *Module) maskGeoObject(geo *openrtb2.Geo) { + // Always preserve country and region (state) as these are not considered PII + // geo.Country and geo.Region are preserved + + // Handle optional geographic fields based on configuration + if !m.cfg.Masking.Geo.PreserveMetro { + geo.Metro = "" + } + if !m.cfg.Masking.Geo.PreserveZip { + geo.ZIP = "" + } + if !m.cfg.Masking.Geo.PreserveCity { + geo.City = "" + } + + // Handle lat/long based on precision setting + if m.cfg.Masking.Geo.LatLongPrecision == 0 { + // Remove completely + geo.Lat = nil + geo.Lon = nil + } else if geo.Lat != nil && geo.Lon != nil { + // Truncate to specified precision + truncatedLat := m.truncateCoordinate(*geo.Lat, m.cfg.Masking.Geo.LatLongPrecision) + truncatedLon := m.truncateCoordinate(*geo.Lon, m.cfg.Masking.Geo.LatLongPrecision) + geo.Lat = &truncatedLat + geo.Lon = &truncatedLon + } + + // Always remove high-precision location data + geo.Accuracy = 0 // GPS accuracy radius could reveal precision +} + +// truncateCoordinate truncates a coordinate to the specified number of decimal places +func (m *Module) truncateCoordinate(coord float64, precision int) float64 { + if precision <= 0 || precision > 4 { + return 0 + } + + multiplier := math.Pow(10, float64(precision)) + // Use math.Trunc instead of math.Floor to handle negative numbers correctly + return math.Trunc(coord*multiplier) / multiplier +} + +// getMaskingSummary returns a summary of what fields would be masked for analytics/debugging +func (m *Module) getMaskingSummary() map[string]interface{} { + if !m.cfg.Masking.Enabled { + return map[string]interface{}{"enabled": false} + } + + return map[string]interface{}{ + "enabled": true, + "geo": map[string]interface{}{ + "preserve_metro": m.cfg.Masking.Geo.PreserveMetro, + "preserve_zip": m.cfg.Masking.Geo.PreserveZip, + "preserve_city": m.cfg.Masking.Geo.PreserveCity, + "lat_long_precision": m.cfg.Masking.Geo.LatLongPrecision, + }, + "user": map[string]interface{}{ + "preserve_eids": m.cfg.Masking.User.PreserveEids, + }, + "device": map[string]interface{}{ + "preserve_mobile_ids": m.cfg.Masking.Device.PreserveMobileIds, + }, + "always_removed": []string{ + "device.ip", "device.ipv6", "user.id", "user.buyeruid", + "user.yob", "user.gender", "user.data", "user.keywords", "geo.accuracy", + }, + "never_removed": []string{ + "geo.country", "geo.region", "device.devicetype", "device.os", + "device.browser", "device.make", "device.model", "site.*", "app.*", "imp.*", + }, + } +} diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go new file mode 100644 index 0000000000..ce1bd48fd1 --- /dev/null +++ b/modules/scope3/rtd/module.go @@ -0,0 +1,484 @@ +// Package scope3 implements a Prebid Server module for Scope3 RTD +package scope3 + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "hash" + "maps" + "net/http" + "slices" + "strings" + "sync" + "time" + + "github.com/coocood/freecache" + "github.com/golang/glog" + jsoniter "github.com/json-iterator/go" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/hooks/hookanalytics" + "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v3/util/iterutil" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +// Builder is the entry point for the module +// This is called by Prebid Server to initialize the module +func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, error) { + var cfg Config + if err := jsonutil.Unmarshal(config, &cfg); err != nil { + return nil, fmt.Errorf("failed to unmarshal config: %w", err) + } + + if cfg.Endpoint == "" { + cfg.Endpoint = "https://rtdp.scope3.com/prebid/rtii" + } + if cfg.Timeout == 0 { + cfg.Timeout = 1000 // 1000ms default + } + if cfg.CacheTTL == 0 { + cfg.CacheTTL = 60 // 60 seconds default + } + + // Set masking defaults and validate configuration + if cfg.Masking.Enabled { + // Validate and set geo precision (max 4 decimal places for privacy) + if cfg.Masking.Geo.LatLongPrecision == 0 { + cfg.Masking.Geo.LatLongPrecision = 2 // 2 decimal places default (~1.1km precision) + } else if cfg.Masking.Geo.LatLongPrecision > 4 { + return nil, errors.New("lat_long_precision cannot exceed 4 decimal places for privacy protection") + } else if cfg.Masking.Geo.LatLongPrecision < 0 { + return nil, errors.New("lat_long_precision cannot be negative") + } + + // Set default EID allowlist if empty + if len(cfg.Masking.User.PreserveEids) == 0 { + // Default to preserving common identity providers + cfg.Masking.User.PreserveEids = []string{"liveramp.com", "uidapi.com", "id5-sync.com"} + } + + // Set default preserve values for geo fields + if !cfg.Masking.Geo.PreserveMetro && !cfg.Masking.Geo.PreserveZip && !cfg.Masking.Geo.PreserveCity { + cfg.Masking.Geo.PreserveMetro = true + cfg.Masking.Geo.PreserveZip = true + } + } + + return &Module{ + cfg: cfg, + httpClient: &http.Client{ + Timeout: time.Duration(cfg.Timeout) * time.Millisecond, + Transport: deps.HTTPClient.Transport, + }, + cache: freecache.NewCache(10 * 1024 * 1024), + sha256Pool: &sync.Pool{ + New: func() any { + return sha256.New() + }, + }, + }, nil +} + +const ( + // keys for miCtx + asyncRequestKey = "scope3.AsyncRequest" +) + +var ( + // Declare hooks + _ hookstage.Entrypoint = (*Module)(nil) + _ hookstage.RawAuctionRequest = (*Module)(nil) + _ hookstage.AuctionResponse = (*Module)(nil) +) + +// Config holds module configuration +type Config struct { + Endpoint string `json:"endpoint"` + AuthKey string `json:"auth_key"` + Timeout int `json:"timeout_ms"` + CacheTTL int `json:"cache_ttl_seconds"` // Cache segments for this many seconds + AddToTargeting bool `json:"add_to_targeting"` // Add segments as individual targeting keys + Masking MaskingConfig `json:"masking"` // Privacy masking configuration +} + +// MaskingConfig controls what user data is masked before sending to Scope3 +type MaskingConfig struct { + Enabled bool `json:"enabled"` + Geo GeoMaskingConfig `json:"geo"` + User UserMaskingConfig `json:"user"` + Device DeviceMaskingConfig `json:"device"` +} + +// GeoMaskingConfig controls geographic data masking +type GeoMaskingConfig struct { + PreserveMetro bool `json:"preserve_metro"` // DMA code (default: true) + PreserveZip bool `json:"preserve_zip"` // Postal code (default: true) + PreserveCity bool `json:"preserve_city"` // City name (default: false) + LatLongPrecision int `json:"lat_long_precision"` // Decimal places for lat/long (0-4, default: 2) +} + +// UserMaskingConfig controls user data masking +type UserMaskingConfig struct { + PreserveEids []string `json:"preserve_eids"` // List of EID sources to preserve +} + +// DeviceMaskingConfig controls device data masking +type DeviceMaskingConfig struct { + PreserveMobileIds bool `json:"preserve_mobile_ids"` // Keep mobile advertising IDs (default: false) +} + +type userExt struct { + Eids []openrtb2.EID `json:"eids"` + RampID string `json:"rampid"` + LiverampIDL string `json:"liveramp_idl"` + ATSEnvelope string `json:"ats_envelope"` + RampIDEnvelope string `json:"rampId_envelope"` +} + +// Response types for Scope3 API +type Scope3Response struct { + Data []Scope3Data `json:"data"` +} + +type Scope3Data struct { + Destination string `json:"destination"` + Imp []Scope3ImpData `json:"imp"` +} + +type Scope3ImpData struct { + ID string `json:"id"` + Ext *Scope3Ext `json:"ext,omitempty"` +} + +type Scope3Ext struct { + Scope3 *Scope3ExtData `json:"scope3"` +} + +type Scope3ExtData struct { + Segments []Scope3Segment `json:"segments"` +} + +type Scope3Segment struct { + ID string `json:"id"` +} + +// Module implements the Scope3 RTD module +type Module struct { + cfg Config + httpClient *http.Client + cache *freecache.Cache + // sha256Pool provides a pool of reusable SHA-256 hash instances for performance + sha256Pool *sync.Pool +} + +// HandleEntrypointHook initializes the module context with a sync.Map for storing segments +func (m *Module) HandleEntrypointHook( + ctx context.Context, + miCtx hookstage.ModuleInvocationContext, + payload hookstage.EntrypointPayload, +) (hookstage.HookResult[hookstage.EntrypointPayload], error) { + // Initialize module context with sync.Map for thread-safe segment storage + return hookstage.HookResult[hookstage.EntrypointPayload]{ + ModuleContext: hookstage.ModuleContext{ + asyncRequestKey: m.NewAsyncRequest(payload.Request), + }, + }, nil +} + +// HandleRawAuctionHook is called early in the auction to fetch Scope3 data +func (m *Module) HandleRawAuctionHook( + ctx context.Context, + miCtx hookstage.ModuleInvocationContext, + payload hookstage.RawAuctionRequestPayload, +) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) { + var ret hookstage.HookResult[hookstage.RawAuctionRequestPayload] + analyticsNamePrefix := "HandleRawAuctionHook." + + asyncRequest, ok := miCtx.ModuleContext[asyncRequestKey].(*AsyncRequest) + if !ok { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + asyncRequestKey, + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": "failed to get async request from module context"}, + }}, + }}, + } + return ret, nil + } + + // Parse OpenRTB request here rather than HandleProcessedAuctionHook to get a copy to avoid parallel mutation issues + var bidRequest openrtb2.BidRequest + if err := jsonutil.Unmarshal(payload, &bidRequest); err != nil { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + "bidRequest.unmarshal", + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": err.Error()}, + }}, + }}, + } + return ret, nil + } + + // Start async request to Scope3 + asyncRequest.fetchScope3SegmentsAsync(&bidRequest) + + return ret, nil +} + +// HandleAuctionResponseHook adds targeting data to the auction response +func (m *Module) HandleAuctionResponseHook( + ctx context.Context, + miCtx hookstage.ModuleInvocationContext, + payload hookstage.AuctionResponsePayload, +) (hookstage.HookResult[hookstage.AuctionResponsePayload], error) { + analyticsNamePrefix := "HandleAuctionResponseHook." + var ret hookstage.HookResult[hookstage.AuctionResponsePayload] + asyncRequest, ok := miCtx.ModuleContext[asyncRequestKey].(*AsyncRequest) + if !ok { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + asyncRequestKey, + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": "failed to get async request from module context"}, + }}, + }}, + } + return ret, nil + } + // Ensure we cancel the request context always to free resources + defer asyncRequest.Cancel() + + // Check if a request was made + if asyncRequest.Done == nil { + return ret, nil + } + + // Wait for the async request to complete + select { + case <-asyncRequest.Done: + // Continue with processing + case <-ctx.Done(): + return ret, nil // Context cancelled, exit gracefully + } + + // Get results + segments, err := asyncRequest.Segments, asyncRequest.Err + if err != nil { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + "scope3_fetch", + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": err.Error()}, + }}, + }}, + } + return ret, nil + } + + if len(segments) == 0 { + return ret, nil + } + + // Add segments to the auction response + ret.ChangeSet.AddMutation( + func(payload hookstage.AuctionResponsePayload) (hookstage.AuctionResponsePayload, error) { + // Add Scope3 segments to the response ext so publisher can use them + if payload.BidResponse.Ext == nil { + payload.BidResponse.Ext = json.RawMessage("{}") + } + + var extMap map[string]interface{} + if err = jsonutil.Unmarshal(payload.BidResponse.Ext, &extMap); err != nil { + extMap = make(map[string]interface{}) + } + + // Add segments as individual targeting keys for GAM integration + if m.cfg.AddToTargeting { + prebidMap, ok := extMap["prebid"].(map[string]interface{}) + if !ok { + prebidMap = make(map[string]interface{}) + extMap["prebid"] = prebidMap + } + targetingMap, ok := prebidMap["targeting"].(map[string]interface{}) + if !ok { + targetingMap = make(map[string]interface{}) + prebidMap["targeting"] = targetingMap + } + // Add each segment as individual targeting key + for _, segment := range segments { + targetingMap[segment] = "true" + } + } + + // Always add to a dedicated scope3 section for publisher flexibility + extMap["scope3"] = map[string]interface{}{ + "segments": segments, + } + + extResp, err := jsonutil.Marshal(extMap) + if err == nil { + payload.BidResponse.Ext = extResp + } + + return payload, nil + }, + hookstage.MutationUpdate, + "ext", + ) + + return ret, nil +} + +// fetchScope3Segments calls the Scope3 API and extracts segments +func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.BidRequest) ([]string, error) { + // Create cache key based on relevant user identifiers and site context + cacheKey := []byte(m.createCacheKey(bidRequest)) + + // Check cache first + if segments, err := m.cache.Get(cacheKey); err == nil { + return strings.Split(string(segments), ","), nil + } + + // Apply privacy masking before sending to Scope3 + requestToSend := bidRequest + if m.cfg.Masking.Enabled { + maskedRequest := m.maskBidRequest(bidRequest) + if maskedRequest == nil { + // Masking failed - don't send request to prevent data leakage + return nil, errors.New("failed to mask bid request for privacy protection") + } + requestToSend = maskedRequest + } + + // Marshal the (potentially masked) bid request + requestBody, err := jsonutil.Marshal(requestToSend) + if err != nil { + return nil, err + } + + // Create HTTP request + req, err := http.NewRequestWithContext(ctx, "POST", m.cfg.Endpoint, bytes.NewReader(requestBody)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-scope3-auth", m.cfg.AuthKey) + + // Make the request + resp, err := m.httpClient.Do(req) + if err != nil { + return nil, err + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("scope3 returned status %d", resp.StatusCode) + } + + // Parse response + var scope3Resp Scope3Response + if err = jsoniter.ConfigCompatibleWithStandardLibrary.NewDecoder(resp.Body).Decode(&scope3Resp); err != nil { + return nil, err + } + + // Extract unique segments (exclude destination) + segmentMap := make(map[string]bool) + for data := range iterutil.SlicePointerValues(scope3Resp.Data) { + // Extract actual segments from impression-level data + for imp := range iterutil.SlicePointerValues(data.Imp) { + if imp.Ext != nil && imp.Ext.Scope3 != nil { + for segment := range iterutil.SlicePointerValues(imp.Ext.Scope3.Segments) { + segmentMap[segment.ID] = true + } + } + } + } + + // Convert to slice + segments := slices.AppendSeq(make([]string, 0, len(segmentMap)), maps.Keys(segmentMap)) + + // Cache the result + err = m.cache.Set(cacheKey, []byte(strings.Join(segments, ",")), m.cfg.CacheTTL) + if err != nil { + glog.Infof("could not set segments in cache: %v", err) + } + + return segments, nil +} + +// createCacheKey generates a cache key based on non-sensitive context and identifiers +// Note: Uses only privacy-safe identifiers to prevent correlation attacks +func (m *Module) createCacheKey(bidRequest *openrtb2.BidRequest) string { + hasher := m.sha256Pool.Get().(hash.Hash) + hasher.Reset() + defer m.sha256Pool.Put(hasher) + + // Include site/app information (not sensitive) + if bidRequest.Site != nil { + hasher.Write([]byte("site:" + bidRequest.Site.Domain)) + if bidRequest.Site.Page != "" { + hasher.Write([]byte("page:" + bidRequest.Site.Page)) + } + } + if bidRequest.App != nil { + hasher.Write([]byte("app:" + bidRequest.App.Bundle)) + } + + // Include user identifiers for per-user caching + hasPrivacySafeID := false + if bidRequest.User != nil && bidRequest.User.Ext != nil { + var userExtension userExt + if err := jsonutil.Unmarshal(bidRequest.User.Ext, &userExtension); err == nil { + // Include LiveRamp identifiers (these are privacy-safe for caching) + for eid := range iterutil.SlicePointerValues(userExtension.Eids) { + if eid.Source == "liveramp.com" && len(eid.UIDs) > 0 { + hasher.Write([]byte("eid:rampid:" + eid.UIDs[0].ID)) + hasPrivacySafeID = true + } + } + + // Include other privacy-safe identifier types + if userExtension.RampID != "" { + hasher.Write([]byte("eid:rampid:" + userExtension.RampID)) + hasPrivacySafeID = true + } + if userExtension.LiverampIDL != "" { + hasher.Write([]byte("eid:ats:" + userExtension.LiverampIDL)) + hasPrivacySafeID = true + } + } + } + + // If no privacy-safe identifiers are available, use hashed user.id for per-user caching + if !hasPrivacySafeID && bidRequest.User != nil && bidRequest.User.ID != "" { + userHasher := m.sha256Pool.Get().(hash.Hash) + userHasher.Reset() + defer m.sha256Pool.Put(userHasher) + + userHasher.Write([]byte("user_id:" + bidRequest.User.ID)) + hasher.Write([]byte("hashed_user_id:" + hex.EncodeToString(userHasher.Sum(nil)))) + } + + return hex.EncodeToString(hasher.Sum(nil)) +} diff --git a/modules/scope3/rtd/module_test.go b/modules/scope3/rtd/module_test.go new file mode 100644 index 0000000000..47638a01bc --- /dev/null +++ b/modules/scope3/rtd/module_test.go @@ -0,0 +1,1427 @@ +package scope3 + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "sync" + "testing" + "time" + + "github.com/coocood/freecache" + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func getTestModuleDeps(t *testing.T) moduledeps.ModuleDeps { + t.Helper() + return moduledeps.ModuleDeps{ + HTTPClient: http.DefaultClient, + } +} + +func getTestEntrypointPayload(t *testing.T) hookstage.EntrypointPayload { + body := []byte(`{}`) + return hookstage.EntrypointPayload{ + Request: httptest.NewRequest(http.MethodPost, "/openrtb2/auction", bytes.NewBuffer(body)), + Body: body, + } +} + +func TestBuilder(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "auth_key": "test-key", + "timeout_ms": 1000, + "cache_ttl_seconds": 60, + "add_to_targeting": false + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.NoError(t, err) + assert.NotNil(t, module) + assert.IsType(t, &Module{}, module) + + m := module.(*Module) + assert.Equal(t, "https://rtdp.scope3.com/amazonaps/rtii", m.cfg.Endpoint) + assert.Equal(t, "test-key", m.cfg.AuthKey) + assert.Equal(t, 1000, m.cfg.Timeout) + assert.Equal(t, 60, m.cfg.CacheTTL) + assert.Equal(t, false, m.cfg.AddToTargeting) + assert.NotNil(t, m.cache) +} + +func TestBuilderInvalidConfig(t *testing.T) { + config := json.RawMessage(`invalid json`) + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + + module, err := Builder(config, deps) + + assert.Error(t, err) + assert.Nil(t, module) +} + +func TestHandleEntrypointHook(t *testing.T) { + module := &Module{} + ctx := context.Background() + miCtx := hookstage.ModuleInvocationContext{} + payload := getTestEntrypointPayload(t) + + result, err := module.HandleEntrypointHook(ctx, miCtx, payload) + + assert.NoError(t, err) + assert.NotNil(t, result.ModuleContext[asyncRequestKey]) +} + +func TestHandleAuctionResponseHook_NoSegments(t *testing.T) { + module := &Module{} + ctx := context.Background() + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + "segments": &sync.Map{}, + }, + } + payload := hookstage.AuctionResponsePayload{} + + result, err := module.HandleAuctionResponseHook(ctx, miCtx, payload) + + assert.NoError(t, err) + assert.Empty(t, result.ChangeSet) +} + +func TestBuilderDefaults(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "auth_key": "test-key" + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.NoError(t, err) + m := module.(*Module) + assert.Equal(t, "https://rtdp.scope3.com/prebid/rtii", m.cfg.Endpoint) + assert.Equal(t, 1000, m.cfg.Timeout) + assert.Equal(t, 60, m.cfg.CacheTTL) + assert.Equal(t, false, m.cfg.AddToTargeting) +} + +func TestScope3APIIntegration(t *testing.T) { + // Create mock Scope3 API server + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify request method and headers + assert.Equal(t, "POST", r.Method) + assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + assert.Equal(t, "test-auth-key", r.Header.Get("x-scope3-auth")) + + // Return mock Scope3 response with segments + response := `{ + "data": [ + { + "destination": "triplelift.com", + "imp": [ + { + "id": "test-imp-1", + "ext": { + "scope3": { + "segments": [ + {"id": "gmp_eligible"}, + {"id": "gmp_plus_eligible"} + ] + } + } + } + ] + } + ] + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with mock server endpoint + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "cache_ttl_seconds": 60, + "add_to_targeting": false + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Create test bid request + width := int64(300) + height := int64(250) + bidRequest := &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test-page", + }, + User: &openrtb2.User{ + ID: "test-user", + Ext: json.RawMessage(`{ + "eids": [ + { + "source": "liveramp.com", + "uids": [{"id": "test-ramp-id"}] + } + ] + }`), + }, + } + + // Test fetchScope3Segments + ctx := context.Background() + segments, err := module.fetchScope3Segments(ctx, bidRequest) + require.NoError(t, err) + assert.Len(t, segments, 2) + assert.Contains(t, segments, "gmp_eligible") + assert.Contains(t, segments, "gmp_plus_eligible") + assert.NotContains(t, segments, "triplelift.com") // Should not include destination +} + +func TestScope3APIIntegrationWithTargeting(t *testing.T) { + // Create mock server that returns segments + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{ + "data": [ + { + "destination": "triplelift.com", + "imp": [ + { + "id": "test-imp-1", + "ext": { + "scope3": { + "segments": [ + {"id": "test_segment_1"}, + {"id": "test_segment_2"} + ] + } + } + } + ] + } + ] + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with targeting enabled + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "add_to_targeting": true + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Test full hook workflow + ctx := context.Background() + + // Test entrypoint hook + entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) + require.NoError(t, err) + assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + + // Create test request payload + width := int64(300) + height := int64(250) + bidRequest := openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + } + requestPayload, _ := json.Marshal(bidRequest) + + // Test raw auction hook + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: entrypointResult.ModuleContext, + } + _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + require.NoError(t, err) + + // Test auction response hook + responsePayload := hookstage.AuctionResponsePayload{ + BidResponse: &openrtb2.BidResponse{ + ID: "test-response", + Ext: json.RawMessage(`{}`), + }, + } + + responseResult, err := module.HandleAuctionResponseHook(ctx, miCtx, responsePayload) + require.NoError(t, err) + + // Verify the response was modified + assert.True(t, len(responseResult.ChangeSet.Mutations()) > 0) + + // Apply the mutations and check the result + modifiedPayload := responsePayload + for _, mutation := range responseResult.ChangeSet.Mutations() { + var err error + modifiedPayload, err = mutation.Apply(modifiedPayload) + require.NoError(t, err) + } + + // Parse the modified response + var extMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.Ext, &extMap) + require.NoError(t, err) + + // Verify scope3 section exists + scope3Data, exists := extMap["scope3"].(map[string]interface{}) + require.True(t, exists) + segments, exists := scope3Data["segments"].([]interface{}) + require.True(t, exists) + assert.Len(t, segments, 2) + + // Verify targeting section exists (add_to_targeting: true) + prebidData, exists := extMap["prebid"].(map[string]interface{}) + require.True(t, exists) + targetingData, exists := prebidData["targeting"].(map[string]interface{}) + require.True(t, exists) + + // Check individual targeting keys + assert.Equal(t, "true", targetingData["test_segment_1"]) + assert.Equal(t, "true", targetingData["test_segment_2"]) +} + +func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { + // Create mock server that returns segments + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{ + "data": [ + { + "destination": "triplelift.com", + "imp": [ + { + "id": "test-imp-1", + "ext": { + "scope3": { + "segments": [ + {"id": "test_segment_1"}, + {"id": "test_segment_2"} + ] + } + } + } + ] + } + ] + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with targeting enabled + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "add_to_targeting": true + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Test full hook workflow + ctx := context.Background() + + // Test entrypoint hook + entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) + require.NoError(t, err) + assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + + // Create test request payload + width := int64(300) + height := int64(250) + bidRequest := openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + } + requestPayload, _ := json.Marshal(bidRequest) + + // Test raw auction hook + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: entrypointResult.ModuleContext, + } + _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + require.NoError(t, err) + + // Test auction response hook + responsePayload := hookstage.AuctionResponsePayload{ + BidResponse: &openrtb2.BidResponse{ + ID: "test-response", + Ext: json.RawMessage(`{"prebid":{"targeting":{"segment_existing":"true"}}}`), + }, + } + + responseResult, err := module.HandleAuctionResponseHook(ctx, miCtx, responsePayload) + require.NoError(t, err) + + // Verify the response was modified + assert.True(t, len(responseResult.ChangeSet.Mutations()) > 0) + + // Apply the mutations and check the result + modifiedPayload := responsePayload + for _, mutation := range responseResult.ChangeSet.Mutations() { + var err error + modifiedPayload, err = mutation.Apply(modifiedPayload) + require.NoError(t, err) + } + + // Parse the modified response + var extMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.Ext, &extMap) + require.NoError(t, err) + + // Verify scope3 section exists + scope3Data, exists := extMap["scope3"].(map[string]interface{}) + require.True(t, exists) + segments, exists := scope3Data["segments"].([]interface{}) + require.True(t, exists) + assert.Len(t, segments, 2) + + // Verify targeting section exists (add_to_targeting: true) + prebidData, exists := extMap["prebid"].(map[string]interface{}) + require.True(t, exists) + targetingData, exists := prebidData["targeting"].(map[string]interface{}) + require.True(t, exists) + + // Check individual targeting keys + assert.Equal(t, "true", targetingData["segment_existing"]) + assert.Equal(t, "true", targetingData["test_segment_1"]) + assert.Equal(t, "true", targetingData["test_segment_2"]) +} + +func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { + // Create mock server that returns segments + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{ + "data": [ + { + "destination": "triplelift.com", + "imp": [ + { + "id": "test-imp-1", + "ext": { + "scope3": { + "segments": [ + {"id": "test_segment_1"}, + {"id": "test_segment_2"} + ] + } + } + } + ] + } + ] + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with targeting enabled + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "add_to_targeting": true + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Test full hook workflow + ctx := context.Background() + + // Test entrypoint hook + entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) + require.NoError(t, err) + assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + + // Create test request payload + width := int64(300) + height := int64(250) + bidRequest := openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + } + requestPayload, _ := json.Marshal(bidRequest) + + // Test raw auction hook + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: entrypointResult.ModuleContext, + } + _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + require.NoError(t, err) + + // Test auction response hook + responsePayload := hookstage.AuctionResponsePayload{ + BidResponse: &openrtb2.BidResponse{ + ID: "test-response", + Ext: json.RawMessage(`{"prebid":{"something_else":"true"}}`), + }, + } + + responseResult, err := module.HandleAuctionResponseHook(ctx, miCtx, responsePayload) + require.NoError(t, err) + + // Verify the response was modified + assert.True(t, len(responseResult.ChangeSet.Mutations()) > 0) + + // Apply the mutations and check the result + modifiedPayload := responsePayload + for _, mutation := range responseResult.ChangeSet.Mutations() { + var err error + modifiedPayload, err = mutation.Apply(modifiedPayload) + require.NoError(t, err) + } + + // Parse the modified response + var extMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.Ext, &extMap) + require.NoError(t, err) + + // Verify scope3 section exists + scope3Data, exists := extMap["scope3"].(map[string]interface{}) + require.True(t, exists) + segments, exists := scope3Data["segments"].([]interface{}) + require.True(t, exists) + assert.Len(t, segments, 2) + + // Verify targeting section exists (add_to_targeting: true) + prebidData, exists := extMap["prebid"].(map[string]interface{}) + require.True(t, exists) + targetingData, exists := prebidData["targeting"].(map[string]interface{}) + require.True(t, exists) + + // Check individual targeting keys + assert.Equal(t, "true", targetingData["test_segment_1"]) + assert.Equal(t, "true", targetingData["test_segment_2"]) +} + +func TestScope3APIError(t *testing.T) { + // Create mock server that returns an error + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("Internal Server Error")) + })) + defer mockServer.Close() + + // Create module with mock server + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000 + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Test that API errors are handled gracefully + bidRequest := &openrtb2.BidRequest{ + ID: "test-auction", + Site: &openrtb2.Site{Domain: "example.com"}, + } + + ctx := context.Background() + segments, err := module.fetchScope3Segments(ctx, bidRequest) + assert.Error(t, err) + assert.Empty(t, segments) + assert.Contains(t, err.Error(), "scope3 returned status 500") +} + +// MASKING TESTS + +func TestBuilderWithMasking(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "auth_key": "test-key", + "timeout_ms": 1000, + "cache_ttl_seconds": 60, + "add_to_targeting": false, + "masking": { + "enabled": true, + "geo": { + "preserve_metro": true, + "preserve_zip": false, + "preserve_city": true, + "lat_long_precision": 3 + }, + "user": { + "preserve_eids": ["liveramp.com", "custom.com"] + }, + "device": { + "preserve_mobile_ids": true + } + } + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.NoError(t, err) + assert.NotNil(t, module) + + m := module.(*Module) + assert.Equal(t, true, m.cfg.Masking.Enabled) + assert.Equal(t, true, m.cfg.Masking.Geo.PreserveMetro) + assert.Equal(t, false, m.cfg.Masking.Geo.PreserveZip) + assert.Equal(t, true, m.cfg.Masking.Geo.PreserveCity) + assert.Equal(t, 3, m.cfg.Masking.Geo.LatLongPrecision) + assert.Equal(t, []string{"liveramp.com", "custom.com"}, m.cfg.Masking.User.PreserveEids) + assert.Equal(t, true, m.cfg.Masking.Device.PreserveMobileIds) +} + +func TestBuilderMaskingDefaults(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "auth_key": "test-key", + "masking": { + "enabled": true + } + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.NoError(t, err) + m := module.(*Module) + + // Check defaults are applied + assert.Equal(t, true, m.cfg.Masking.Enabled) + assert.Equal(t, 2, m.cfg.Masking.Geo.LatLongPrecision) // Default precision + assert.Equal(t, true, m.cfg.Masking.Geo.PreserveMetro) // Default preserve + assert.Equal(t, true, m.cfg.Masking.Geo.PreserveZip) // Default preserve + assert.Equal(t, []string{"liveramp.com", "uidapi.com", "id5-sync.com"}, m.cfg.Masking.User.PreserveEids) + assert.Equal(t, false, m.cfg.Masking.Device.PreserveMobileIds) // Default false +} + +func TestMaskBidRequest_Disabled(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{Enabled: false}, + }, + } + + lat := 37.774929 + lon := -122.419416 + original := &openrtb2.BidRequest{ + User: &openrtb2.User{ + ID: "publisher-user-123", + }, + Device: &openrtb2.Device{ + IP: "192.168.1.1", + IFA: "12345-67890", + Geo: &openrtb2.Geo{ + Lat: &lat, + Lon: &lon, + }, + }, + } + + result := module.maskBidRequest(original) + + // Should return exact same request when disabled + assert.Equal(t, original, result) +} + +func TestMaskUser(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + User: UserMaskingConfig{ + PreserveEids: []string{"liveramp.com", "uidapi.com"}, + }, + }, + }, + } + + original := &openrtb2.BidRequest{ + User: &openrtb2.User{ + ID: "publisher-user-123", + BuyerUID: "exchange-user-456", + Yob: 1990, + Gender: "M", + Keywords: "sports,automotive", + Data: []openrtb2.Data{{ + ID: "segment1", + Name: "sports_fans", + }}, + EIDs: []openrtb2.EID{ + {Source: "liveramp.com", UIDs: []openrtb2.UID{{ID: "ramp123"}}}, + {Source: "blocked.com", UIDs: []openrtb2.UID{{ID: "blocked456"}}}, + {Source: "uidapi.com", UIDs: []openrtb2.UID{{ID: "uid789"}}}, + }, + }, + } + + module.maskUser(original) + + // Check that sensitive fields are removed + assert.Equal(t, "", original.User.ID) + assert.Equal(t, "", original.User.BuyerUID) + assert.Equal(t, int64(0), original.User.Yob) + assert.Equal(t, "", original.User.Gender) + assert.Equal(t, "", original.User.Keywords) + assert.Nil(t, original.User.Data) + + // Check that eids are filtered correctly + assert.Len(t, original.User.EIDs, 2) + assert.Equal(t, "liveramp.com", original.User.EIDs[0].Source) + assert.Equal(t, "uidapi.com", original.User.EIDs[1].Source) +} + +func TestFilterEids(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + User: UserMaskingConfig{ + PreserveEids: []string{"liveramp.com", "id5-sync.com"}, + }, + }, + }, + } + + eids := []openrtb2.EID{ + {Source: "liveramp.com", UIDs: []openrtb2.UID{{ID: "ramp123"}}}, + {Source: "blocked.com", UIDs: []openrtb2.UID{{ID: "blocked456"}}}, + {Source: "id5-sync.com", UIDs: []openrtb2.UID{{ID: "id5789"}}}, + {Source: "another-blocked.com", UIDs: []openrtb2.UID{{ID: "blocked999"}}}, + } + + result := module.filterEids(eids) + + assert.Len(t, result, 2) + assert.Equal(t, "liveramp.com", result[0].Source) + assert.Equal(t, "id5-sync.com", result[1].Source) +} + +func TestFilterEids_EmptyAllowlist(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + User: UserMaskingConfig{ + PreserveEids: []string{}, + }, + }, + }, + } + + eids := []openrtb2.EID{ + {Source: "liveramp.com", UIDs: []openrtb2.UID{{ID: "ramp123"}}}, + {Source: "blocked.com", UIDs: []openrtb2.UID{{ID: "blocked456"}}}, + } + + result := module.filterEids(eids) + assert.Len(t, result, 0) +} + +func TestMaskDevice(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Device: DeviceMaskingConfig{ + PreserveMobileIds: false, + }, + }, + }, + } + + original := &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + IP: "192.168.1.1", + IPv6: "2001:db8::1", + IFA: "12345-67890", + DPIDMD5: "abc123", + DPIDSHA1: "def456", + DIDMD5: "ghi789", + DIDSHA1: "jkl012", + MACMD5: "mno345", + MACSHA1: "pqr678", + DeviceType: 1, + OS: "iOS", + Make: "Apple", + Model: "iPhone", + }, + } + + module.maskDevice(original) + + // Check sensitive fields are removed + assert.Equal(t, "", original.Device.IP) + assert.Equal(t, "", original.Device.IPv6) + assert.Equal(t, "", original.Device.IFA) + assert.Equal(t, "", original.Device.DPIDMD5) + assert.Equal(t, "", original.Device.DPIDSHA1) + assert.Equal(t, "", original.Device.DIDMD5) + assert.Equal(t, "", original.Device.DIDSHA1) + assert.Equal(t, "", original.Device.MACMD5) + assert.Equal(t, "", original.Device.MACSHA1) + + // Check targeting-safe fields are preserved + assert.Equal(t, adcom1.DeviceType(1), original.Device.DeviceType) + assert.Equal(t, "iOS", original.Device.OS) + assert.Equal(t, "Apple", original.Device.Make) + assert.Equal(t, "iPhone", original.Device.Model) +} + +func TestMaskDevice_PreserveMobileIds(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Device: DeviceMaskingConfig{ + PreserveMobileIds: true, + }, + }, + }, + } + + original := &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + IP: "192.168.1.1", + IFA: "12345-67890", + DPIDMD5: "abc123", + DPIDSHA1: "def456", + }, + } + + module.maskDevice(original) + + // IP should still be removed + assert.Equal(t, "", original.Device.IP) + + // But mobile IDs should be preserved + assert.Equal(t, "12345-67890", original.Device.IFA) + assert.Equal(t, "abc123", original.Device.DPIDMD5) + assert.Equal(t, "def456", original.Device.DPIDSHA1) +} + +func TestMaskGeoObject(t *testing.T) { + lat := 37.774929 + lon := -122.419416 + accuracy := int64(10) + + tests := []struct { + name string + config GeoMaskingConfig + expectedLat *float64 + expectedLon *float64 + expectedMetro string + expectedZip string + expectedCity string + expectedAccuracy int64 + }{ + { + name: "precision_0_removes_coordinates", + config: GeoMaskingConfig{ + LatLongPrecision: 0, + PreserveMetro: true, + PreserveZip: true, + PreserveCity: true, + }, + expectedLat: nil, + expectedLon: nil, + expectedMetro: "807", // preserved + expectedZip: "94102", // preserved + expectedCity: "San Francisco", // preserved + expectedAccuracy: 0, // always removed + }, + { + name: "precision_2_truncates_coordinates", + config: GeoMaskingConfig{ + LatLongPrecision: 2, + PreserveMetro: false, + PreserveZip: false, + PreserveCity: false, + }, + expectedLat: &[]float64{37.77}[0], // truncated to 2 decimals + expectedLon: &[]float64{-122.41}[0], // truncated to 2 decimals + expectedMetro: "", // not preserved + expectedZip: "", // not preserved + expectedCity: "", // not preserved + expectedAccuracy: 0, // always removed + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Geo: tt.config, + }, + }, + } + + geo := &openrtb2.Geo{ + Lat: &lat, + Lon: &lon, + Country: "USA", // always preserved + Region: "CA", // always preserved + Metro: "807", + ZIP: "94102", + City: "San Francisco", + Accuracy: accuracy, + } + + module.maskGeoObject(geo) + + // Check coordinates + if tt.expectedLat == nil { + assert.Nil(t, geo.Lat) + } else { + require.NotNil(t, geo.Lat) + assert.InDelta(t, *tt.expectedLat, *geo.Lat, 0.001) + } + + if tt.expectedLon == nil { + assert.Nil(t, geo.Lon) + } else { + require.NotNil(t, geo.Lon) + assert.InDelta(t, *tt.expectedLon, *geo.Lon, 0.001) + } + + // Check other fields + assert.Equal(t, "USA", geo.Country) // always preserved + assert.Equal(t, "CA", geo.Region) // always preserved + assert.Equal(t, tt.expectedMetro, geo.Metro) + assert.Equal(t, tt.expectedZip, geo.ZIP) + assert.Equal(t, tt.expectedCity, geo.City) + assert.Equal(t, int64(0), geo.Accuracy) // always removed + }) + } +} + +func TestTruncateCoordinate(t *testing.T) { + module := &Module{} + + tests := []struct { + coord float64 + precision int + expected float64 + }{ + {37.774929, 0, 0}, + {37.774929, 1, 37.7}, + {37.774929, 2, 37.77}, + {37.774929, 3, 37.774}, + {37.774929, 4, 37.7749}, + {-122.419416, 2, -122.41}, + {-122.419416, 3, -122.419}, + } + + for _, tt := range tests { + t.Run(fmt.Sprintf("coord_%.6f_precision_%d", tt.coord, tt.precision), func(t *testing.T) { + result := module.truncateCoordinate(tt.coord, tt.precision) + assert.InDelta(t, tt.expected, result, 0.0001) + }) + } +} + +func TestMaskBidRequest_FullIntegration(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Geo: GeoMaskingConfig{ + PreserveMetro: true, + PreserveZip: false, + PreserveCity: false, + LatLongPrecision: 2, + }, + User: UserMaskingConfig{ + PreserveEids: []string{"liveramp.com"}, + }, + Device: DeviceMaskingConfig{ + PreserveMobileIds: false, + }, + }, + }, + } + + lat := 37.774929 + lon := -122.419416 + original := &openrtb2.BidRequest{ + ID: "test-request", + User: &openrtb2.User{ + ID: "publisher-user-123", + BuyerUID: "exchange-user-456", + Gender: "M", + EIDs: []openrtb2.EID{ + {Source: "liveramp.com", UIDs: []openrtb2.UID{{ID: "ramp123"}}}, + {Source: "blocked.com", UIDs: []openrtb2.UID{{ID: "blocked456"}}}, + }, + }, + Device: &openrtb2.Device{ + IP: "192.168.1.1", + IFA: "12345-67890", + DeviceType: 1, + OS: "iOS", + Geo: &openrtb2.Geo{ + Lat: &lat, + Lon: &lon, + Country: "USA", + Region: "CA", + Metro: "807", + ZIP: "94102", + City: "San Francisco", + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + } + + result := module.maskBidRequest(original) + + // Should be different object (deep copy) + assert.NotEqual(t, original, result) + + // Check user masking + assert.Equal(t, "", result.User.ID) + assert.Equal(t, "", result.User.BuyerUID) + assert.Equal(t, "", result.User.Gender) + assert.Len(t, result.User.EIDs, 1) + assert.Equal(t, "liveramp.com", result.User.EIDs[0].Source) + + // Check device masking + assert.Equal(t, "", result.Device.IP) + assert.Equal(t, "", result.Device.IFA) + assert.Equal(t, adcom1.DeviceType(1), result.Device.DeviceType) // preserved + assert.Equal(t, "iOS", result.Device.OS) // preserved + + // Check geo masking + assert.Equal(t, "USA", result.Device.Geo.Country) // preserved + assert.Equal(t, "CA", result.Device.Geo.Region) // preserved + assert.Equal(t, "807", result.Device.Geo.Metro) // preserved + assert.Equal(t, "", result.Device.Geo.ZIP) // not preserved + assert.Equal(t, "", result.Device.Geo.City) // not preserved + assert.InDelta(t, 37.77, *result.Device.Geo.Lat, 0.001) // truncated + assert.InDelta(t, -122.41, *result.Device.Geo.Lon, 0.001) // truncated + + // Check site is preserved completely + assert.Equal(t, "example.com", result.Site.Domain) + assert.Equal(t, "https://example.com/test", result.Site.Page) + + // Original should be unchanged + assert.Equal(t, "publisher-user-123", original.User.ID) + assert.Equal(t, "192.168.1.1", original.Device.IP) + assert.InDelta(t, 37.774929, *original.Device.Geo.Lat, 0.000001) +} + +func TestGetMaskingSummary(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Geo: GeoMaskingConfig{ + PreserveMetro: true, + PreserveZip: false, + LatLongPrecision: 3, + }, + User: UserMaskingConfig{ + PreserveEids: []string{"liveramp.com", "uidapi.com"}, + }, + Device: DeviceMaskingConfig{ + PreserveMobileIds: true, + }, + }, + }, + } + + summary := module.getMaskingSummary() + + assert.Equal(t, true, summary["enabled"]) + + geoConfig, ok := summary["geo"].(map[string]interface{}) + require.True(t, ok) + assert.Equal(t, true, geoConfig["preserve_metro"]) + assert.Equal(t, false, geoConfig["preserve_zip"]) + assert.Equal(t, 3, geoConfig["lat_long_precision"]) + + userConfig, ok := summary["user"].(map[string]interface{}) + require.True(t, ok) + assert.Equal(t, []string{"liveramp.com", "uidapi.com"}, userConfig["preserve_eids"]) + + deviceConfig, ok := summary["device"].(map[string]interface{}) + require.True(t, ok) + assert.Equal(t, true, deviceConfig["preserve_mobile_ids"]) +} + +func TestGetMaskingSummary_Disabled(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{Enabled: false}, + }, + } + + summary := module.getMaskingSummary() + assert.Equal(t, map[string]interface{}{"enabled": false}, summary) +} + +func TestMaskGeo_UserGeoOnly(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{ + Enabled: true, + Geo: GeoMaskingConfig{ + PreserveMetro: false, + PreserveZip: false, + LatLongPrecision: 2, + }, + }, + }, + } + + lat := 40.7128 + lon := -74.0060 + original := &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{ + Lat: &lat, + Lon: &lon, + Country: "USA", + Region: "NY", + Metro: "501", + ZIP: "10001", + }, + }, + // No device geo + Device: &openrtb2.Device{ + OS: "iOS", + }, + } + + module.maskGeo(original) + + // Check user geo was masked + assert.Equal(t, "USA", original.User.Geo.Country) // preserved + assert.Equal(t, "NY", original.User.Geo.Region) // preserved + assert.Equal(t, "", original.User.Geo.Metro) // removed + assert.Equal(t, "", original.User.Geo.ZIP) // removed + assert.InDelta(t, 40.71, *original.User.Geo.Lat, 0.001) // truncated + assert.InDelta(t, -74.00, *original.User.Geo.Lon, 0.001) // truncated +} + +func TestTruncateCoordinate_EdgeCases(t *testing.T) { + module := &Module{} + + // Test precision out of range + assert.Equal(t, float64(0), module.truncateCoordinate(37.774929, -1)) + assert.Equal(t, float64(0), module.truncateCoordinate(37.774929, 5)) + assert.Equal(t, float64(0), module.truncateCoordinate(37.774929, 0)) + + // Test zero coordinate + assert.Equal(t, float64(0), module.truncateCoordinate(0.0, 2)) +} + +func TestMaskDevice_NoDevice(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{Enabled: true}, + }, + } + + original := &openrtb2.BidRequest{ + ID: "test", + User: &openrtb2.User{ID: "user-123"}, + // No device + } + + module.maskDevice(original) + + // Should not crash when device is nil + assert.Nil(t, original.Device) +} + +func TestMaskUser_NoUser(t *testing.T) { + module := &Module{ + cfg: Config{ + Masking: MaskingConfig{Enabled: true}, + }, + } + + original := &openrtb2.BidRequest{ + ID: "test", + // No user + Device: &openrtb2.Device{IP: "192.168.1.1"}, + } + + module.maskUser(original) + + // Should not crash when user is nil + assert.Nil(t, original.User) +} + +func TestBuilderConfigValidation_GeoPrecisionTooHigh(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "auth_key": "test-key", + "masking": { + "enabled": true, + "geo": { + "lat_long_precision": 5 + } + } + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "cannot exceed 4 decimal places") + assert.Nil(t, module) +} + +func TestBuilderConfigValidation_GeoPrecisionNegative(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "auth_key": "test-key", + "masking": { + "enabled": true, + "geo": { + "lat_long_precision": -1 + } + } + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "cannot be negative") + assert.Nil(t, module) +} + +func TestBuilderConfigValidation_GeoPrecisionValid(t *testing.T) { + config := json.RawMessage(`{ + "enabled": true, + "auth_key": "test-key", + "masking": { + "enabled": true, + "geo": { + "lat_long_precision": 4 + } + } + }`) + + deps := moduledeps.ModuleDeps{HTTPClient: http.DefaultClient} + module, err := Builder(config, deps) + + assert.NoError(t, err) + assert.NotNil(t, module) + + m := module.(*Module) + assert.Equal(t, 4, m.cfg.Masking.Geo.LatLongPrecision) +} + +func TestCreateCacheKey_HashedUserID(t *testing.T) { + module := &Module{ + sha256Pool: &sync.Pool{ + New: func() any { + return sha256.New() + }, + }, + } + + // Create request with user ID (no privacy-safe identifiers) + bidRequest := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + User: &openrtb2.User{ + ID: "sensitive-user-id-123", // This should be hashed in cache key + }, + } + + key1 := module.createCacheKey(bidRequest) + + // Create another request with different user ID + bidRequest2 := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + User: &openrtb2.User{ + ID: "different-user-id-456", // Different hash should produce different key + }, + } + + key2 := module.createCacheKey(bidRequest2) + + // Keys should be different since user IDs are different (per-user caching) + assert.NotEqual(t, key1, key2, "Cache keys should be different for different user IDs to enable per-user caching") + + // Create request with same user ID to verify consistency + bidRequest3 := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + User: &openrtb2.User{ + ID: "sensitive-user-id-123", // Same as first request + }, + } + + key3 := module.createCacheKey(bidRequest3) + + // Should match first key for same user + assert.Equal(t, key1, key3, "Cache keys should be consistent for same user ID") + + // Verify key is SHA-256 length (64 hex characters) + assert.Len(t, key1, 64, "Cache key should be SHA-256 hash (64 characters)") +} + +func TestCreateCacheKey_PrivacySafeIdentifiersPriority(t *testing.T) { + module := &Module{ + sha256Pool: &sync.Pool{ + New: func() any { + return sha256.New() + }, + }, + } + + // Create request with both user.id and privacy-safe identifiers + userExtBytes, _ := jsonutil.Marshal(userExt{ + RampID: "ramp_abc123", + }) + + bidRequest := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + User: &openrtb2.User{ + ID: "user-id-should-not-be-used", + Ext: userExtBytes, + }, + } + + key1 := module.createCacheKey(bidRequest) + + // Create another request with same privacy-safe ID but different user.id + bidRequest2 := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + User: &openrtb2.User{ + ID: "completely-different-user-id", + Ext: userExtBytes, // Same RampID + }, + } + + key2 := module.createCacheKey(bidRequest2) + + // Keys should be the same since privacy-safe identifiers take priority + assert.Equal(t, key1, key2, "Cache keys should be same when privacy-safe identifiers match, regardless of user.id") +} + +func TestFetchScope3Segments_MaskingFailure(t *testing.T) { + // Create a test server that simulates API response + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{"data": []}` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + module := &Module{ + cfg: Config{ + Endpoint: mockServer.URL, + AuthKey: "test-key", + Timeout: 1000, + Masking: MaskingConfig{Enabled: true}, + }, + httpClient: &http.Client{ + Timeout: 1 * time.Second, + }, + cache: freecache.NewCache(10), + sha256Pool: &sync.Pool{ + New: func() any { + return sha256.New() + }, + }, + } + + // Create a request that should work normally + bidRequest := &openrtb2.BidRequest{ + ID: "test-request", + User: &openrtb2.User{ + ID: "user-123", + }, + } + + ctx := context.Background() + + // This should succeed now that we have proper HTTP client setup + // The masking should work correctly and not cause errors + segments, err := module.fetchScope3Segments(ctx, bidRequest) + + // Should succeed with proper setup + assert.NoError(t, err) + assert.NotNil(t, segments) +} From 6a9b4b29156e528114e2c525c885869767675b6a Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Tue, 23 Sep 2025 15:40:21 -0400 Subject: [PATCH 089/272] Metrics: Add connection dial metrics by adapter (#4528) --- config/config.go | 4 ++ config/config_test.go | 3 + exchange/bidder.go | 46 +++++++++++---- exchange/bidder_test.go | 1 + metrics/config/metrics.go | 18 ++++++ metrics/go_metrics.go | 15 +++++ metrics/go_metrics_test.go | 2 + metrics/metrics.go | 2 + metrics/metrics_mock.go | 8 +++ metrics/prometheus/preload.go | 8 +++ metrics/prometheus/prometheus.go | 27 +++++++++ metrics/prometheus/prometheus_test.go | 85 +++++++++++++++++++++------ 12 files changed, 188 insertions(+), 31 deletions(-) diff --git a/config/config.go b/config/config.go index d36f0e442a..a013bdc5a4 100644 --- a/config/config.go +++ b/config/config.go @@ -592,6 +592,9 @@ type DisabledMetrics struct { // that were created or reused. AdapterConnectionMetrics bool `mapstructure:"adapter_connections_metrics"` + // True if we don't want to collect metrics on dial time and dial errors + AdapterConnectionDialMetrics bool `mapstructure:"adapter_connection_dial_metrics"` + // True if we don't want to collect the per adapter buyer UID scrubbed metric AdapterBuyerUIDScrubbed bool `mapstructure:"adapter_buyeruid_scrubbed"` @@ -993,6 +996,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("metrics.disabled_metrics.account_debug", true) v.SetDefault("metrics.disabled_metrics.account_stored_responses", true) v.SetDefault("metrics.disabled_metrics.adapter_connections_metrics", true) + v.SetDefault("metrics.disabled_metrics.adapter_connection_dial_metrics", true) v.SetDefault("metrics.disabled_metrics.adapter_buyeruid_scrubbed", true) v.SetDefault("metrics.disabled_metrics.adapter_gdpr_request_blocked", false) v.SetDefault("metrics.influxdb.host", "") diff --git a/config/config_test.go b/config/config_test.go index b9cb99ad72..64c741eebe 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -158,6 +158,7 @@ func TestDefaults(t *testing.T) { cmpBools(t, "account_debug", true, cfg.Metrics.Disabled.AccountDebug) cmpBools(t, "account_stored_responses", true, cfg.Metrics.Disabled.AccountStoredResponses) cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) + cmpBools(t, "adapter_connection_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) cmpBools(t, "adapter_buyeruid_scrubbed", true, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) cmpBools(t, "adapter_gdpr_request_blocked", false, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) cmpStrings(t, "certificates_file", "", cfg.PemCertsFile) @@ -483,6 +484,7 @@ metrics: account_debug: false account_stored_responses: false adapter_connections_metrics: true + adapter_connection_dial_metrics: true adapter_buyeruid_scrubbed: false adapter_gdpr_request_blocked: true account_modules_metrics: true @@ -918,6 +920,7 @@ func TestFullConfig(t *testing.T) { cmpBools(t, "account_debug", false, cfg.Metrics.Disabled.AccountDebug) cmpBools(t, "account_stored_responses", false, cfg.Metrics.Disabled.AccountStoredResponses) cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) + cmpBools(t, "adapter_connection_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) cmpBools(t, "adapter_buyeruid_scrubbed", false, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) cmpBools(t, "adapter_gdpr_request_blocked", true, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) cmpStrings(t, "certificates_file", "/etc/ssl/cert.pem", cfg.PemCertsFile) diff --git a/exchange/bidder.go b/exchange/bidder.go index a305a0e84b..8e2c235dc9 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -111,10 +111,11 @@ func AdaptBidder(bidder adapters.Bidder, client *http.Client, cfg *config.Config Client: client, me: me, config: bidderAdapterConfig{ - Debug: cfg.Debug, - DisableConnMetrics: cfg.Metrics.Disabled.AdapterConnectionMetrics, - DebugInfo: config.DebugInfo{Allow: parseDebugInfo(debugInfo)}, - EndpointCompression: endpointCompression, + Debug: cfg.Debug, + DisableConnMetrics: cfg.Metrics.Disabled.AdapterConnectionMetrics, + DisableConnDialMetrics: cfg.Metrics.Disabled.AdapterConnectionDialMetrics, + DebugInfo: config.DebugInfo{Allow: parseDebugInfo(debugInfo)}, + EndpointCompression: endpointCompression, ThrottleConfig: bidderAdapterThrottleConfig{ enabled: cfg.Client.Throttle.EnableThrottling, simulateOnly: cfg.Client.Throttle.SimulateThrottlingOnly, @@ -152,11 +153,12 @@ type BidderAdapter struct { } type bidderAdapterConfig struct { - Debug config.Debug - DisableConnMetrics bool - DebugInfo config.DebugInfo - EndpointCompression string - ThrottleConfig bidderAdapterThrottleConfig + Debug config.Debug + DisableConnMetrics bool + DisableConnDialMetrics bool + DebugInfo config.DebugInfo + EndpointCompression string + ThrottleConfig bidderAdapterThrottleConfig } type bidderAdapterThrottleConfig struct { @@ -596,7 +598,7 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re // If adapter connection metrics are not disabled, add the client trace // to get complete connection info into our metrics if !bidder.config.DisableConnMetrics { - ctx = bidder.addClientTrace(ctx) + ctx = bidder.addClientTrace(ctx, bidder.config.DisableConnDialMetrics) } bidder.me.RecordOverheadTime(metrics.PreBidder, time.Since(bidderRequestStartTime)) @@ -728,8 +730,8 @@ type httpCallInfo struct { // This function adds an httptrace.ClientTrace object to the context so, if connection with the bidder // endpoint is established, we can keep track of whether the connection was newly created, reused, and // the time from the connection request, to the connection creation. -func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context { - var connStart, dnsStart, tlsStart time.Time +func (bidder *BidderAdapter) addClientTrace(ctx context.Context, dialMetricsDisabled bool) context.Context { + var connStart, dnsStart, tlsStart, dialStart time.Time trace := &httptrace.ClientTrace{ // GetConn is called before a connection is created or retrieved from an idle pool @@ -774,6 +776,26 @@ func (bidder *BidderAdapter) addClientTrace(ctx context.Context) context.Context bidder.me.RecordTLSHandshakeTime(tlsHandshakeTime) }, } + + if !dialMetricsDisabled { + // ConnectStart is called when a new connection's Dial begins. + trace.ConnectStart = func(network, addr string) { + dialStart = time.Now() + } + + // ConnectDone is called when a new connection's Dial completes. + // The provided err indicates whether the connection completed + // successfully. + trace.ConnectDone = func(network, addr string, err error) { + dialStartTime := time.Since(dialStart) + bidder.me.RecordAdapterConnectionDialTime(bidder.BidderName, dialStartTime) + + if err != nil { + bidder.me.RecordAdapterConnectionDialError(bidder.BidderName) + } + } + } + return httptrace.WithClientTrace(ctx, trace) } diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index 50e919c2a6..2d9caf097c 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -2085,6 +2085,7 @@ func TestCallRecordAdapterConnections(t *testing.T) { mockMetricEngine.On("RecordAdapterConnections", expectedAdapterName, false, mock.MatchedBy(compareConnWaitTime)).Once() mockMetricEngine.On("RecordOverheadTime", metrics.PreBidder, mock.Anything).Once() mockMetricEngine.On("RecordBidderServerResponseTime", mock.Anything).Once() + mockMetricEngine.On("RecordAdapterConnectionDialTime", mock.Anything, mock.Anything).Once() // Run requestBid using an http.Client with a mock handler bidder := AdaptBidder(bidderImpl, server.Client(), &config.Configuration{}, mockMetricEngine, openrtb_ext.BidderAppnexus, nil, "") diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index 1a378e0faf..cb039155bf 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -384,6 +384,18 @@ func (me *MultiMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderN } } +func (me *MultiMetricsEngine) RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) { + for _, thisME := range *me { + thisME.RecordAdapterConnectionDialError(adapterName) + } +} + +func (me *MultiMetricsEngine) RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) { + for _, thisME := range *me { + thisME.RecordAdapterConnectionDialTime(adapterName, dialStartTime) + } +} + // NilMetricsEngine implements the MetricsEngine interface where no metrics are actually captured. This is // used if no metric backend is configured and also for tests. type NilMetricsEngine struct{} @@ -566,3 +578,9 @@ func (me *NilMetricsEngine) RecordModuleTimeout(labels metrics.ModuleLabels) { // RecordAdapterThrottled as a noop func (me *NilMetricsEngine) RecordAdapterThrottled(adapter openrtb_ext.BidderName) { } + +func (me *NilMetricsEngine) RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) { +} + +func (me *NilMetricsEngine) RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) { +} diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index e6fa3ec550..2be2675272 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -101,6 +101,8 @@ type AdapterMetrics struct { ConnCreated metrics.Counter ConnReused metrics.Counter ConnWaitTime metrics.Timer + ConnDialErrors metrics.Counter + ConnDialTime metrics.Timer BuyerUIDScrubbed metrics.Meter GDPRRequestBlocked metrics.Meter ThrottledMeter metrics.Meter @@ -423,6 +425,8 @@ func makeBlankAdapterMetrics(disabledMetrics config.DisabledMetrics) *AdapterMet newAdapter.ConnCreated = metrics.NilCounter{} newAdapter.ConnReused = metrics.NilCounter{} newAdapter.ConnWaitTime = &metrics.NilTimer{} + newAdapter.ConnDialErrors = metrics.NilCounter{} + newAdapter.ConnDialTime = &metrics.NilTimer{} } if !disabledMetrics.AdapterBuyerUIDScrubbed { newAdapter.BuyerUIDScrubbed = blankMeter @@ -498,6 +502,9 @@ func registerAdapterMetrics(registry metrics.Registry, adapterOrAccount string, am.ConnCreated = metrics.GetOrRegisterCounter(fmt.Sprintf("%[1]s.%[2]s.connections_created", adapterOrAccount, exchange), registry) am.ConnReused = metrics.GetOrRegisterCounter(fmt.Sprintf("%[1]s.%[2]s.connections_reused", adapterOrAccount, exchange), registry) am.ConnWaitTime = metrics.GetOrRegisterTimer(fmt.Sprintf("%[1]s.%[2]s.connection_wait_time", adapterOrAccount, exchange), registry) + am.ConnDialErrors = metrics.GetOrRegisterCounter(fmt.Sprintf("%[1]s.%[2]s.connection_dial_err", adapterOrAccount, exchange), registry) + am.ConnDialTime = metrics.GetOrRegisterTimer(fmt.Sprintf("%[1]s.%[2]s.connection_dial_time", adapterOrAccount, exchange), registry) + for err := range am.ErrorMeters { am.ErrorMeters[err] = metrics.GetOrRegisterMeter(fmt.Sprintf("%s.%s.requests.%s", adapterOrAccount, exchange, err), registry) } @@ -776,6 +783,14 @@ func (me *Metrics) RecordAdapterConnections(adapterName openrtb_ext.BidderName, am.ConnWaitTime.Update(connWaitTime) } +func (m *Metrics) RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) { + m.AdapterMetrics[strings.ToLower(string(adapterName))].ConnDialErrors.Inc(1) +} + +func (m *Metrics) RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) { + m.AdapterMetrics[strings.ToLower(string(adapterName))].ConnDialTime.Update(dialStartTime) +} + func (me *Metrics) RecordDNSTime(dnsLookupTime time.Duration) { me.DNSLookupTimer.Update(dnsLookupTime) } diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index e32bf930c1..2fcec9cb6d 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -141,6 +141,8 @@ func ensureContainsAdapterMetrics(t *testing.T, registry metrics.Registry, name ensureContains(t, registry, name+".connections_created", adapterMetrics.ConnCreated) ensureContains(t, registry, name+".connections_reused", adapterMetrics.ConnReused) ensureContains(t, registry, name+".connection_wait_time", adapterMetrics.ConnWaitTime) + ensureContains(t, registry, name+".connection_dial_err", adapterMetrics.ConnDialErrors) + ensureContains(t, registry, name+".connection_dial_time", adapterMetrics.ConnDialTime) ensureContains(t, registry, name+".response.validation.size.err", adapterMetrics.BidValidationCreativeSizeErrorMeter) ensureContains(t, registry, name+".response.validation.size.warn", adapterMetrics.BidValidationCreativeSizeWarnMeter) diff --git a/metrics/metrics.go b/metrics/metrics.go index c4079c3fe6..054bf8940a 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -511,4 +511,6 @@ type MetricsEngine interface { RecordModuleExecutionError(labels ModuleLabels) RecordModuleTimeout(labels ModuleLabels) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) + RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) + RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) } diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index 911bcaf4b6..09fa605166 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -234,3 +234,11 @@ func (me *MetricsEngineMock) RecordModuleTimeout(labels ModuleLabels) { func (me *MetricsEngineMock) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { me.Called(adapterName) } + +func (me *MetricsEngineMock) RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) { + me.Called() +} + +func (me *MetricsEngineMock) RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) { + me.Called(adapterName, dialStartTime) +} diff --git a/metrics/prometheus/preload.go b/metrics/prometheus/preload.go index c59dfeece0..40e8c5b233 100644 --- a/metrics/prometheus/preload.go +++ b/metrics/prometheus/preload.go @@ -184,6 +184,14 @@ func preloadLabelValues(m *Metrics, syncerKeys []string, moduleStageNames map[st preloadLabelValuesForHistogram(m.adapterConnectionWaitTime, map[string][]string{ adapterLabel: adapterValues, }) + + preloadLabelValuesForCounter(m.adapterConnectionDialErrors, map[string][]string{ + adapterLabel: adapterValues, + }) + + preloadLabelValuesForHistogram(m.adapterConnectionDialTime, map[string][]string{ + adapterLabel: adapterValues, + }) } preloadLabelValuesForHistogram(m.adapterRequestsTimer, map[string][]string{ diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index fb8c5ce2e5..873161df38 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -79,6 +79,8 @@ type Metrics struct { adapterBidResponseSecureMarkupError *prometheus.CounterVec adapterBidResponseSecureMarkupWarn *prometheus.CounterVec adapterThrottled *prometheus.CounterVec + adapterConnectionDialErrors *prometheus.CounterVec + adapterConnectionDialTime *prometheus.HistogramVec // Syncer Metrics syncerRequests *prometheus.CounterVec @@ -419,6 +421,19 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "Seconds from when the connection was requested until it is either created or reused", []string{adapterLabel}, standardTimeBuckets) + + if !metrics.metricsDisabled.AdapterConnectionDialMetrics { + metrics.adapterConnectionDialErrors = newCounter(cfg, reg, + "adapter_connection_dial_errors", + "Count when a connection dial returns an error.", + []string{adapterLabel}) + + metrics.adapterConnectionDialTime = newHistogramVec(cfg, reg, + "adapter_connection_dial_time", + "Seconds adapter bidder connection dial lasted", + []string{adapterLabel}, + append(prometheus.DefBuckets, 15, 30)) + } } metrics.adapterBidResponseValidationSizeError = newCounter(cfg, reg, @@ -1125,3 +1140,15 @@ func (m *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { adapterLabel: strings.ToLower(string(adapterName)), }).Inc() } + +func (m *Metrics) RecordAdapterConnectionDialError(adapterName openrtb_ext.BidderName) { + m.adapterConnectionDialErrors.With(prometheus.Labels{ + adapterLabel: strings.ToLower(string(adapterName)), + }).Inc() +} + +func (m *Metrics) RecordAdapterConnectionDialTime(adapterName openrtb_ext.BidderName, dialStartTime time.Duration) { + m.adapterConnectionDialTime.With(prometheus.Labels{ + adapterLabel: strings.ToLower(string(adapterName)), + }).Observe(dialStartTime.Seconds()) +} diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index 78e9b01494..d4edca8858 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -2,6 +2,7 @@ package prometheusmetrics import ( "fmt" + "strings" "testing" "time" @@ -64,17 +65,22 @@ func TestMetricCountGatekeeping(t *testing.T) { // Verify Per-Adapter Cardinality // - This assertion provides a warning for newly added adapter metrics. Threre are 40+ adapters which makes the // cost of new per-adapter metrics rather expensive. Thought should be given when adding new per-adapter metrics. - assert.True(t, perAdapterCardinalityCount <= 31, "Per-Adapter Cardinality count equals %d \n", perAdapterCardinalityCount) + assert.True(t, perAdapterCardinalityCount <= 33, "Per-Adapter Cardinality count equals %d \n", perAdapterCardinalityCount) } func TestConnectionMetrics(t *testing.T) { + adapterName := openrtb_ext.BidderName("anyName") + lowerCasedAdapterName := "anyname" testCases := []struct { - description string - testCase func(m *Metrics) - expectedOpenedCount float64 - expectedOpenedErrorCount float64 - expectedClosedCount float64 - expectedClosedErrorCount float64 + description string + testCase func(m *Metrics) + expectedOpenedCount float64 + expectedOpenedErrorCount float64 + expectedClosedCount float64 + expectedClosedErrorCount float64 + expectedConnectionDialErrors float64 + expectedDialTime float64 + expectedDialTimerCalls uint64 }{ { description: "Open Success", @@ -116,6 +122,21 @@ func TestConnectionMetrics(t *testing.T) { expectedClosedCount: 0, expectedClosedErrorCount: 1, }, + { + description: "connection-dial-ended-and-threw-an-error", + testCase: func(m *Metrics) { + m.RecordAdapterConnectionDialError(adapterName) + }, + expectedConnectionDialErrors: 1, + }, + { + description: "connection-dial-ended-and-was-timed", + testCase: func(m *Metrics) { + m.RecordAdapterConnectionDialTime(adapterName, time.Second) + }, + expectedDialTime: 1, + expectedDialTimerCalls: 1, + }, } for _, test := range testCases { @@ -135,6 +156,20 @@ func TestConnectionMetrics(t *testing.T) { test.expectedClosedErrorCount, prometheus.Labels{ connectionErrorLabel: connectionCloseError, }) + assertCounterVecValue(t, + test.description, + "adapter[anyName]", + m.adapterConnectionDialErrors, + test.expectedConnectionDialErrors, + prometheus.Labels{adapterLabel: lowerCasedAdapterName}, + ) + histogram, found := getHistogramFromHistogramVec(m.adapterConnectionDialTime, + adapterLabel, + strings.ToLower(string(adapterName)), + ) + assert.Equal(t, test.expectedDialTimerCalls > 0, found) + assert.Equal(t, test.expectedDialTimerCalls, histogram.GetSampleCount(), test.description) + assert.Equal(t, test.expectedDialTime, histogram.GetSampleSum(), test.description) } } @@ -157,7 +192,8 @@ func TestRequestMetric(t *testing.T) { requestStatusLabel: string(requestStatus), }) - histogram := getHistogramFromHistogramVec(m.requestsSize, requestEndpointLabel, string(metrics.EndpointAuction)) + histogram, found := getHistogramFromHistogramVec(m.requestsSize, requestEndpointLabel, string(metrics.EndpointAuction)) + assert.True(t, found) assertHistogram(t, "requests_size_auction", histogram, 1, 1024) } @@ -521,7 +557,8 @@ func TestRequestTimeMetric(t *testing.T) { test.testCase(m) - result := getHistogramFromHistogramVec(m.requestsTimer, requestTypeLabel, string(requestType)) + result, found := getHistogramFromHistogramVec(m.requestsTimer, requestTypeLabel, string(requestType)) + assert.True(t, found) assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum) } } @@ -567,7 +604,8 @@ func TestRecordOverheadTimeMetric(t *testing.T) { metric := createMetricsForTesting() for _, test := range testCases { metric.RecordOverheadTime(test.overheadType, time.Duration(test.timeInMs)*time.Millisecond) - resultingHistogram := getHistogramFromHistogramVec(metric.overheadTimer, overheadTypeLabel, test.overheadType.String()) + resultingHistogram, found := getHistogramFromHistogramVec(metric.overheadTimer, overheadTypeLabel, test.overheadType.String()) + assert.True(t, found) assertHistogram(t, test.description, resultingHistogram, test.expectedCount, test.expectedSum) } } @@ -660,10 +698,11 @@ func TestRecordStoredDataFetchTime(t *testing.T) { metricsTimer = m.storedResponsesFetchTimer } - result := getHistogramFromHistogramVec( + result, found := getHistogramFromHistogramVec( metricsTimer, storedDataFetchTypeLabel, string(tt.fetchType)) + assert.True(t, found) assertHistogram(t, tt.description, result, 1, 0.5) } } @@ -841,7 +880,8 @@ func TestRecordAdapterPriceMetric(t *testing.T) { expectedCount := uint64(1) expectedSum := cpm - result := getHistogramFromHistogramVec(m.adapterPrices, adapterLabel, lowerCasedAdapterName) + result, found := getHistogramFromHistogramVec(m.adapterPrices, adapterLabel, lowerCasedAdapterName) + assert.True(t, found) assertHistogram(t, "adapterPrices", result, expectedCount, expectedSum) } @@ -1102,7 +1142,8 @@ func TestAdapterTimeMetric(t *testing.T) { test.testCase(m) - result := getHistogramFromHistogramVec(m.adapterRequestsTimer, adapterLabel, lowerCasedAdapterName) + result, found := getHistogramFromHistogramVec(m.adapterRequestsTimer, adapterLabel, lowerCasedAdapterName) + assert.Equal(t, test.expectedCount > 0, found) assertHistogram(t, test.description, result, test.expectedCount, test.expectedSum) } } @@ -1337,12 +1378,14 @@ func TestPrebidCacheRequestTimeMetric(t *testing.T) { successExpectedCount := uint64(1) successExpectedSum := float64(0.1) - successResult := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "true") + successResult, found := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "true") + assert.True(t, found) assertHistogram(t, "Success", successResult, successExpectedCount, successExpectedSum) errorExpectedCount := uint64(1) errorExpectedSum := float64(0.2) - errorResult := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "false") + errorResult, found := getHistogramFromHistogramVec(m.prebidCacheWriteTimer, successLabel, "false") + assert.True(t, found) assertHistogram(t, "Error", errorResult, errorExpectedCount, errorExpectedSum) } @@ -1627,7 +1670,8 @@ func TestRecordAdapterConnections(t *testing.T) { prometheus.Labels{adapterLabel: lowerCasedAdapterName}) // Assert connection wait time - histogram := getHistogramFromHistogramVec(m.adapterConnectionWaitTime, adapterLabel, lowerCasedAdapterName) + histogram, found := getHistogramFromHistogramVec(m.adapterConnectionWaitTime, adapterLabel, lowerCasedAdapterName) + assert.True(t, found) assert.Equal(t, test.out.expectedConnWaitCount, histogram.GetSampleCount(), assertDesciptions[2]) assert.Equal(t, test.out.expectedConnWaitTime, histogram.GetSampleSum(), assertDesciptions[3]) } @@ -1744,16 +1788,18 @@ func assertCounterVecValue(t *testing.T, description, name string, counterVec *p assertCounterValue(t, description, name, counter, expected) } -func getHistogramFromHistogramVec(histogram *prometheus.HistogramVec, labelKey, labelValue string) dto.Histogram { +func getHistogramFromHistogramVec(histogram *prometheus.HistogramVec, labelKey, labelValue string) (dto.Histogram, bool) { var result dto.Histogram + var found bool processMetrics(histogram, func(m dto.Metric) { for _, label := range m.GetLabel() { if label.GetName() == labelKey && label.GetValue() == labelValue { result = *m.GetHistogram() + found = true } } }) - return result + return result, found } func getHistogramFromHistogramVecByTwoKeys(histogram *prometheus.HistogramVec, label1Key, label1Value, label2Key, label2Value string) dto.Histogram { @@ -2028,7 +2074,8 @@ func TestRecordModuleMetrics(t *testing.T) { }) // now check that the values are correct - result := getHistogramFromHistogramVec(m.moduleDuration[module], stageLabel, stage) + result, found := getHistogramFromHistogramVec(m.moduleDuration[module], stageLabel, stage) + assert.True(t, found) assertHistogram(t, fmt.Sprintf("module_%s_duration", module), result, 1, 0.001) assertCounterVecValue(t, "Module calls performed", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleCalls[module], 1, prometheus.Labels{stageLabel: stage}) assertCounterVecValue(t, "Module calls failed", fmt.Sprintf("%s metric recorded during %s stage", module, stage), m.moduleFailures[module], 1, prometheus.Labels{stageLabel: stage}) From 8137d93a20e1224993faa5e4c37b5a7d111ac701 Mon Sep 17 00:00:00 2001 From: Amit Biton <56631148+amitbiton01@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:55:46 +0300 Subject: [PATCH 090/272] KueezRTB: Remove additionalProperties from schema (#4490) --- adapters/kueezrtb/params_test.go | 1 - static/bidder-params/kueezrtb.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/adapters/kueezrtb/params_test.go b/adapters/kueezrtb/params_test.go index f7b263728f..33e5ea0a64 100644 --- a/adapters/kueezrtb/params_test.go +++ b/adapters/kueezrtb/params_test.go @@ -44,7 +44,6 @@ var invalidParams = []string{ `{"cId": {}`, `{"cId": ""}`, `{"cId": null}`, - `{"cId": "provided_cid_123", "extra": "field"}`, `{"cid": "valid_cid"}`, `{"cId": "invalid_chars_!@#$%^&*()"}`, } diff --git a/static/bidder-params/kueezrtb.json b/static/bidder-params/kueezrtb.json index 742412f088..d8d0b8a733 100644 --- a/static/bidder-params/kueezrtb.json +++ b/static/bidder-params/kueezrtb.json @@ -13,6 +13,5 @@ }, "required": [ "cId" - ], - "additionalProperties": false + ] } \ No newline at end of file From bbaa1b79e01bc868aff5bbd823b41498aaafefbf Mon Sep 17 00:00:00 2001 From: Shane Lacey <shanel262@hotmail.com> Date: Tue, 23 Sep 2025 22:03:19 +0100 Subject: [PATCH 091/272] Kargo: Add email to codepath notification workflow (#4484) Co-authored-by: Nick Llerandi <nick.llerandi@kargo.com> --- .github/workflows/scripts/codepath-notification | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification index a86dccbbd7..8a3bae8dac 100644 --- a/.github/workflows/scripts/codepath-notification +++ b/.github/workflows/scripts/codepath-notification @@ -18,3 +18,4 @@ openx: prebid@openx.com adapters/ix|imp_ix|ix.json|ix.yaml: pdu-supply-prebid@indexexchange.com medianet: prebid@media.net gumgum: prebid@gumgum.com +kargo: kraken@kargo.com From 30ec1b5e6e5701033816be75df9aa5ddab24aed2 Mon Sep 17 00:00:00 2001 From: Sebastien Boisvert <sebastien.boisvert@contxtful.com> Date: Wed, 24 Sep 2025 08:54:08 -0400 Subject: [PATCH 092/272] New Adapter: Contxtful (#4443) Co-authored-by: rufiange <sebastien@rufiange.com> --- adapters/contxtful/contxtful.go | 388 ++ adapters/contxtful/contxtful_relay_test.go | 238 + adapters/contxtful/contxtful_test.go | 4353 +++++++++++++++++ .../exemplary/multiple-impressions.json | 332 ++ .../exemplary/simple-banner.json | 168 + .../exemplary/simple-native.json | 158 + .../contxtfultest/exemplary/video.json | 176 + .../exemplary/with-user-sync.json | 167 + .../buyeruids-map-extraction.json | 158 + .../supplemental/empty-response.json | 103 + .../supplemental/http-204-no-content.json | 98 + .../supplemental/invalid-bidder-params.json | 32 + .../supplemental/invalid-imp-ext.json | 30 + .../supplemental/invalid-response.json | 103 + .../contxtfultest/supplemental/no-adm.json | 124 + .../supplemental/no-currency.json | 142 + .../supplemental/no-mediatype.json | 124 + .../supplemental/trace-format.json | 104 + adapters/contxtful/params_test.go | 47 + exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_contxtful.go | 7 + static/bidder-info/contxtful.yaml | 20 + static/bidder-params/contxtful.json | 19 + 24 files changed, 7095 insertions(+) create mode 100644 adapters/contxtful/contxtful.go create mode 100644 adapters/contxtful/contxtful_relay_test.go create mode 100644 adapters/contxtful/contxtful_test.go create mode 100644 adapters/contxtful/contxtfultest/exemplary/multiple-impressions.json create mode 100644 adapters/contxtful/contxtfultest/exemplary/simple-banner.json create mode 100644 adapters/contxtful/contxtfultest/exemplary/simple-native.json create mode 100644 adapters/contxtful/contxtfultest/exemplary/video.json create mode 100644 adapters/contxtful/contxtfultest/exemplary/with-user-sync.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/buyeruids-map-extraction.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/empty-response.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/http-204-no-content.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/invalid-bidder-params.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/invalid-imp-ext.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/invalid-response.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/no-adm.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/no-currency.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/no-mediatype.json create mode 100644 adapters/contxtful/contxtfultest/supplemental/trace-format.json create mode 100644 adapters/contxtful/params_test.go create mode 100644 openrtb_ext/imp_contxtful.go create mode 100644 static/bidder-info/contxtful.yaml create mode 100644 static/bidder-params/contxtful.json diff --git a/adapters/contxtful/contxtful.go b/adapters/contxtful/contxtful.go new file mode 100644 index 0000000000..3dd8b5b2b9 --- /dev/null +++ b/adapters/contxtful/contxtful.go @@ -0,0 +1,388 @@ +package contxtful + +import ( + "fmt" + "net/http" + "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" +) + +// ContxtfulRequestPayload represents the complete request payload structure +type ContxtfulRequestPayload struct { + ORTB2 *openrtb2.BidRequest `json:"ortb2"` + BidRequests []ContxtfulBidRequest `json:"bidRequests"` + BidderRequest ContxtfulBidderRequest `json:"bidderRequest"` + Config ContxtfulConfig `json:"config"` +} + +// ContxtfulBidRequest represents an individual bid request +type ContxtfulBidRequest struct { + Bidder string `json:"bidder"` + Params ContxtfulBidRequestParams `json:"params"` + BidID string `json:"bidId"` +} + +// ContxtfulBidRequestParams represents the parameters for a bid request +type ContxtfulBidRequestParams struct { + PlacementID string `json:"placementId"` +} + +// ContxtfulBidderRequest represents the bidder request information +type ContxtfulBidderRequest struct { + BidderCode string `json:"bidderCode"` +} + +// ContxtfulConfig represents the configuration section +type ContxtfulConfig struct { + Contxtful ContxtfulConfigDetails `json:"contxtful"` +} + +// ContxtfulConfigDetails represents the detailed configuration +type ContxtfulConfigDetails struct { + Version string `json:"version"` + Customer string `json:"customer"` +} + +// BidExtensions represents the complete bid extensions structure +type BidExtensions struct { + OrigBidCPM float64 `json:"origbidcpm"` + OrigBidCur string `json:"origbidcur"` + Prebid openrtb_ext.ExtBidPrebid `json:"prebid"` +} + +type ContxtfulExchangeBid struct { + RequestID string `json:"requestId"` + CPM float64 `json:"cpm"` + Currency string `json:"currency"` + Width int `json:"width"` + Height int `json:"height"` + CreativeID string `json:"creativeId"` + AdM string `json:"adm"` + TTL int `json:"ttl"` + NetRevenue bool `json:"netRevenue"` + MediaType string `json:"mediaType"` + BidderCode string `json:"bidderCode"` + PlacementID string `json:"placementId"` + TraceId string `json:"traceId,omitempty"` + Random float64 `json:"random,omitempty"` + NURL string `json:"nurl"` + BURL string `json:"burl"` + LURL string `json:"lurl,omitempty"` + Ext jsonutil.RawMessage `json:"ext,omitempty"` +} + +type BidProcessingContext struct { + request *openrtb2.BidRequest + requestData *adapters.RequestData + customerId string + bidderResponse *adapters.BidderResponse + errors []error + // Event URL generation fields + version string + domain string + adRequestID string +} + +type adapter struct { + endpointTemplate *template.Template +} + +// Essential constants +const ( + BidderName = "contxtful" + DefaultVersion = "v1" + FieldBidder = "bidder" + PbsPath = "/pbs/" +) + +// Helper to safely extract bidder parameters from impression extension +func extractBidderParams(impExt jsonutil.RawMessage) (*openrtb_ext.ExtImpContxtful, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(impExt, &bidderExt); err != nil { + return nil, err + } + + var contxtfulParams openrtb_ext.ExtImpContxtful + if err := jsonutil.Unmarshal(bidderExt.Bidder, &contxtfulParams); err != nil { + return nil, err + } + + return &contxtfulParams, nil +} + +// Builder builds a new instance of the Contxtful adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{ + endpointTemplate: template.Must(template.New("endpointTemplate").Parse(config.Endpoint)), + }, nil +} + +// Extract impression parameters (validation handled by JSON schema) +func validateImpressions(request *openrtb2.BidRequest) ([]string, string, []error) { + var errors []error + var customerId string + validPlacements := make([]string, 0, len(request.Imp)) + + for _, imp := range request.Imp { + contxtfulParams, err := extractBidderParams(imp.Ext) + if err != nil { + errors = append(errors, err) + continue + } + + if customerId == "" { + customerId = contxtfulParams.CustomerId + } + validPlacements = append(validPlacements, contxtfulParams.PlacementId) + } + + return validPlacements, customerId, errors +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errors []error + + // Build headers efficiently + headers := http.Header{ + "Content-Type": []string{"application/json;charset=utf-8"}, + "Accept": []string{"application/json"}, + } + + // Build dynamic endpoint URL and validate impressions + endpoint, validPlacements, customerId, endpointErrors := a.buildEndpointURL(request) + errors = append(errors, endpointErrors...) + + if len(validPlacements) == 0 { + return nil, errors + } + + // Create payload + payload := createRequestPayload(request, validPlacements, customerId) + + requestJSON, err := jsonutil.Marshal(payload) + if err != nil { + errors = append(errors, err) + return nil, errors + } + + requestData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: endpoint, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, errors +} + +// buildEndpointURL validates impressions and creates the endpoint URL +func (a *adapter) buildEndpointURL(request *openrtb2.BidRequest) (string, []string, string, []error) { + // Validate impressions and extract parameters + validPlacements, customerId, validationErrors := validateImpressions(request) + + if len(validationErrors) > 0 { + return "", validPlacements, customerId, validationErrors + } + + // Use bidder config customer as primary source for endpoint URL + endpointCustomerId := customerId + + // Build dynamic endpoint URL + endpointParams := macros.EndpointTemplateParams{ + AccountID: endpointCustomerId, + } + endpoint, err := macros.ResolveMacros(a.endpointTemplate, endpointParams) + if err != nil { + return "", validPlacements, customerId, []error{err} + } + + return endpoint, validPlacements, customerId, nil +} + +// Streamlined payload creation +func createRequestPayload(request *openrtb2.BidRequest, validPlacements []string, customerId string) ContxtfulRequestPayload { + // Create clean request copy + requestCopy := *request + + adapterVersion := DefaultVersion + customer := customerId + + uid := extractUserIDForCookie(request) + + // Ensure UID is written to ortb2.user.buyeruid with deep copy + if uid != "" { + // Create a deep copy of the User object to avoid modifying the original + userCopy := *requestCopy.User + requestCopy.User = &userCopy + requestCopy.User.BuyerUID = uid + } + + // Build bid requests + bidRequests := make([]ContxtfulBidRequest, len(request.Imp)) + for i, imp := range request.Imp { + bidRequests[i] = ContxtfulBidRequest{ + Bidder: BidderName, + Params: ContxtfulBidRequestParams{ + PlacementID: validPlacements[i], + }, + BidID: imp.ID, + } + } + + return ContxtfulRequestPayload{ + ORTB2: &requestCopy, + BidRequests: bidRequests, + BidderRequest: ContxtfulBidderRequest{ + BidderCode: BidderName, + }, + Config: ContxtfulConfig{ + Contxtful: ContxtfulConfigDetails{ + Version: adapterVersion, + Customer: customer, + }, + }, + } +} + +// Response format handlers +// Direct response processing without over-engineered handler pattern +func (a *adapter) processResponse(responseBody []byte, ctx *BidProcessingContext) bool { + // Try PrebidJS format first + var prebidBids []ContxtfulExchangeBid + if err := jsonutil.Unmarshal(responseBody, &prebidBids); err == nil && len(prebidBids) > 0 { + return a.processPrebidJSBids(prebidBids, ctx) + } + + return false +} + +func (a *adapter) processPrebidJSBids(prebidBids []ContxtfulExchangeBid, ctx *BidProcessingContext) bool { + for _, prebidBid := range prebidBids { + if prebidBid.CPM == 0 || prebidBid.RequestID == "" { + continue + } + if prebidBid.MediaType == "" { + ctx.errors = append(ctx.errors, &errortypes.BadServerResponse{Message: "bid has no ad media type"}) + continue + } + if prebidBid.AdM == "" { + ctx.errors = append(ctx.errors, &errortypes.BadServerResponse{Message: "bid has no ad markup"}) + continue + } + currency := prebidBid.Currency + if currency == "" { + currency = "USD" + } + + a.createBid(prebidBid, currency, ctx) + + if prebidBid.Currency != "" { + ctx.bidderResponse.Currency = prebidBid.Currency + } + } + return true +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + // Extract domain for event URLs + domain := "" + if request.Site != nil && request.Site.Domain != "" { + domain = request.Site.Domain + } + + ctx := &BidProcessingContext{ + request: request, + requestData: requestData, + bidderResponse: adapters.NewBidderResponse(), + domain: domain, + adRequestID: request.ID, + } + + if a.processResponse(response.Body, ctx) { + return ctx.bidderResponse, ctx.errors + } + + return nil, []error{fmt.Errorf("failed to parse response as Contxtful relay or Prebid.js format")} +} + +// Simplified bid creation using prebid bid struct +func (a *adapter) createBid( + prebidBid ContxtfulExchangeBid, + currency string, + ctx *BidProcessingContext, +) { + // Determine media type from impression + var bidType openrtb_ext.BidType = openrtb_ext.BidTypeBanner + for _, imp := range ctx.request.Imp { + if imp.ID == prebidBid.RequestID { + if imp.Video != nil { + bidType = openrtb_ext.BidTypeVideo + } else if imp.Native != nil { + bidType = openrtb_ext.BidTypeNative + } + break + } + } + + bid := &openrtb2.Bid{ + ID: fmt.Sprintf("%s-%s", BidderName, prebidBid.RequestID), + ImpID: prebidBid.RequestID, + Price: prebidBid.CPM, + AdM: prebidBid.AdM, + W: int64(prebidBid.Width), + H: int64(prebidBid.Height), + CrID: prebidBid.CreativeID, + NURL: prebidBid.NURL, + BURL: prebidBid.BURL, + LURL: prebidBid.LURL, + Ext: prebidBid.Ext, + } + + typedBid := &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + } + + ctx.bidderResponse.Bids = append(ctx.bidderResponse.Bids, typedBid) +} + +func extractUserIDForCookie(request *openrtb2.BidRequest) string { + if request.User == nil { + return "" + } + + // Priority 1: Standard ORTB2 BuyerUID field + if request.User.BuyerUID != "" { + return request.User.BuyerUID + } + + // Priority 2: PBS buyeruids map (simplified navigation) + if request.User.Ext != nil { + var userExt openrtb_ext.ExtUser + if err := jsonutil.Unmarshal(request.User.Ext, &userExt); err == nil { + if userExt.Prebid != nil && userExt.Prebid.BuyerUIDs != nil { + if uid := userExt.Prebid.BuyerUIDs[BidderName]; uid != "" { + return uid + } + } + } + } + + return "" +} diff --git a/adapters/contxtful/contxtful_relay_test.go b/adapters/contxtful/contxtful_relay_test.go new file mode 100644 index 0000000000..61f9773ab5 --- /dev/null +++ b/adapters/contxtful/contxtful_relay_test.go @@ -0,0 +1,238 @@ +package contxtful + +import ( + "encoding/json" + "testing" + + "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/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +// TestContxtfulRelay tests that the adapter correctly transforms input OpenRTB requests +// to the expected format for the Contxtful relay endpoint +func TestContxtfulRelay(t *testing.T) { + // Create a test adapter + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", // Use the dynamic endpoint template + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Load the test OpenRTB request + inputRequest := createTestOpenRTBRequest(t) + + // Execute the adapter's request transformation logic + requestsData, errs := bidder.MakeRequests(inputRequest, &adapters.ExtraRequestInfo{}) + + // Verify no errors occurred + assert.Empty(t, errs, "Expected no errors") + assert.Len(t, requestsData, 1, "Expected one request") + + // Verify the request URI matches what we expect (should be resolved with customerId) + expectedEndpoint := "https://prebid.receptivity.io/v1/pbs/test-customer-123/bid" + assert.Equal(t, expectedEndpoint, requestsData[0].Uri, "Unexpected request URI") + assert.Equal(t, "POST", requestsData[0].Method, "Unexpected HTTP method") + + // Decode the request body to verify structure + var requestBody map[string]interface{} + err := json.Unmarshal(requestsData[0].Body, &requestBody) + assert.NoError(t, err, "Should unmarshal request body without errors") + + // Verify basic structure of the request + assert.Contains(t, requestBody, "ortb2", "Request body should contain ortb2 field") + assert.Equal(t, "1", inputRequest.Imp[0].ID, "Imp ID should be preserved") + + // Verify headers + assert.Equal(t, "application/json;charset=utf-8", requestsData[0].Headers.Get("Content-Type"), "Content-Type header should be set") + assert.Equal(t, "application/json", requestsData[0].Headers.Get("Accept"), "Accept header should be set") +} + +// createTestOpenRTBRequest creates a test OpenRTB request similar to the example provided +func createTestOpenRTBRequest(t *testing.T) *openrtb2.BidRequest { + // Sample request based on the structure provided + rawJson := `{ + "imp": [{ + "ext": { + "data": { + "divId": "/19968336/header-bid-tag-0", + "adg_rtd": { + "adunit_position": "8x151" + }, + "placement": "in_article" + }, + "bidder": { + "placementId": "p10000001", + "customerId": "test-customer-123" + }, + "prebid": { + "adunitcode": "/19968336/header-bid-tag-0" + } + }, + "id": "1", + "banner": { + "topframe": 1, + "format": [{ + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "secure": 1 + }], + "test": 1, + "app": { + "id": "test-app-id", + "bundle": "test.bundle" + }, + "site": { + "domain": "prometheus.receptivity.io", + "publisher": { + "domain": "receptivity.io", + "id": "1" + }, + "page": "https://example.receptivity.io/", + "ext": { + "data": { + "documentLang": "en", + "adg_rtd": { + "uid": "4b9f3464-8177-4b6f-9bf5-baf69be33b10", + "pageviewId": "d3c75c57-3cb5-48d9-b7b6-3ea2e401759b", + "features": { + "page_dimensions": "2034x668", + "viewport_dimensions": "2034x652", + "user_timestamp": "1746128988", + "dom_loading": "512" + }, + "session": { + "rnd": 0.17883197907537263, + "pages": 3, + "new": true, + "vwSmplg": 0, + "vwSmplgNxt": 0, + "expiry": 1746141471202, + "lastActivityTime": 1746139671202, + "id": "45811c08-b3f0-4395-9040-a87077325ced" + } + } + } + } + }, + "device": { + "w": 2560, + "h": 1080, + "dnt": 1, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36", + "language": "fr", + "ext": { + "vpw": 2034, + "vph": 344 + }, + "sua": { + "source": 1, + "platform": { + "brand": "macOS" + }, + "browsers": [{ + "brand": "Chromium", + "version": ["135"] + }, + { + "brand": "Not-A.Brand", + "version": ["8"] + } + ], + "mobile": 0 + } + }, + "ext": { + "prebid": { + "auctiontimestamp": 1746143432301, + "targeting": { + "includewinners": true, + "includebidderkeys": false + }, + "bidderconfig": [{ + "bidders": ["pubmatic"], + "config": { + } + }], + "debug": true, + "channel": { + "name": "pbjs", + "version": "v9.39.0-pre" + }, + "createtids": false + }, + "tmaxmax": 3000 + }, + "id": "3dc63dbf-dcfa-4645-bf2a-23d32fb759d2", + "tmax": 1000 + }` + + var req openrtb2.BidRequest + err := json.Unmarshal([]byte(rawJson), &req) + assert.NoError(t, err, "Should unmarshal test request without errors") + + return &req +} + +// TestContxtfulTransformStructure performs a deeper test of the request transformation structure +func TestContxtfulTransformStructure(t *testing.T) { + // Create a test adapter + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", // Use the dynamic endpoint template + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Load the test OpenRTB request + inputRequest := createTestOpenRTBRequest(t) + + // Execute the adapter's request transformation logic + requestsData, errs := bidder.MakeRequests(inputRequest, &adapters.ExtraRequestInfo{}) + + if errs != nil && len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Verify we got a request back + assert.Len(t, requestsData, 1, "Expected one request") + + // Decode the request body to inspect the structure in detail + var requestBody map[string]interface{} + err := json.Unmarshal(requestsData[0].Body, &requestBody) + assert.NoError(t, err, "Should unmarshal request body without errors") + + // Check for the expected fields in the transformed request + assert.Contains(t, requestBody, "ortb2", "Request should contain ortb2") + + // Check that ortb2 is a map + _, ok := requestBody["ortb2"].(map[string]interface{}) + assert.True(t, ok, "ortb2 should be a map") + + // Verify the bidRequests field structure + assert.Contains(t, requestBody, "bidRequests", "Request should contain bidRequests") + bidRequests, ok := requestBody["bidRequests"].([]interface{}) + assert.True(t, ok, "bidRequests should be an array") + assert.GreaterOrEqual(t, len(bidRequests), 1, "bidRequests should have at least one entry") + + // Verify bidRequest contains the expected fields + bidRequest, ok := bidRequests[0].(map[string]interface{}) + assert.True(t, ok, "bidRequest should be a map") + assert.Contains(t, bidRequest, "bidder", "bidRequest should contain bidder") + assert.Contains(t, bidRequest, "params", "bidRequest should contain params") + + // Verify the bidderRequest field is present + assert.Contains(t, requestBody, "bidderRequest", "Request should contain bidderRequest") +} diff --git a/adapters/contxtful/contxtful_test.go b/adapters/contxtful/contxtful_test.go new file mode 100644 index 0000000000..b1fa229b6d --- /dev/null +++ b/adapters/contxtful/contxtful_test.go @@ -0,0 +1,4353 @@ +package contxtful + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "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/v3/util/jsonutil" + "github.com/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "contxtfultest", bidder) +} + +func TestPayloadFormat(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create a test request + requestJSON := `{ + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer-123" + } + } + } + ], + "site": { + "id": "test-site", + "page": "https://example.com" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify the payload structure + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + // Check required top-level fields + if _, exists := payload["ortb2"]; !exists { + t.Error("Payload missing 'ortb2' field") + } + if _, exists := payload["bidRequests"]; !exists { + t.Error("Payload missing 'bidRequests' field") + } + if _, exists := payload["bidderRequest"]; !exists { + t.Error("Payload missing 'bidderRequest' field") + } + if _, exists := payload["config"]; !exists { + t.Error("Payload missing 'config' field") + } + + // Verify bidRequests structure + bidRequests, ok := payload["bidRequests"].([]interface{}) + if !ok || len(bidRequests) != 1 { + t.Error("bidRequests should be an array with one element") + } + + bidRequest, ok := bidRequests[0].(map[string]interface{}) + if !ok { + t.Error("bidRequest should be an object") + } + + // Check bidRequest fields + if bidRequest["bidder"] != "contxtful" { + t.Error("bidRequest.bidder should be 'contxtful'") + } + + params, ok := bidRequest["params"].(map[string]interface{}) + if !ok { + t.Error("bidRequest.params should be an object") + } + + if params["placementId"] != "test-placement" { + t.Error("bidRequest.params.placementId should be 'test-placement'") + } + + // Verify endpoint URL + expectedURL := "https://prebid.receptivity.io/v1/pbs/test-customer-123/bid" + if requests[0].Uri != expectedURL { + t.Errorf("Expected URL %s, got %s", expectedURL, requests[0].Uri) + } +} + +// TestCookieFlowWithBuyerUID tests cookie handling when BuyerUID is present +func TestCookieFlowWithBuyerUID(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + requestJSON := `{ + "id": "test-request-cookie", + "imp": [ + { + "id": "test-imp-cookie", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "placementId": "test-placement-cookie", + "customerId": "test-customer-cookie" + } + } + } + ], + "site": { + "id": "test-site-cookie", + "page": "https://example.com/cookie-test" + }, + "user": { + "id": "test-user-123", + "buyeruid": "contxtful-v1-eyJjdXN0b21lciI6IkNVU1RPTUVSMTIzIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCJ9LCJ2ZXJzaW9uIjoidjEifQ==" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify user data in payload + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + if user["buyeruid"] != "contxtful-v1-eyJjdXN0b21lciI6IkNVU1RPTUVSMTIzIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCJ9LCJ2ZXJzaW9uIjoidjEifQ==" { + t.Error("ortb2.user.buyeruid should be preserved") + } +} + +// TestCookieFlowWithoutBuyerUID tests cookie handling when BuyerUID is not present +func TestCookieFlowWithoutBuyerUID(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + requestJSON := `{ + "id": "test-request-no-cookie", + "imp": [ + { + "id": "test-imp-no-cookie", + "banner": { + "format": [{"w": 320, "h": 50}] + }, + "ext": { + "bidder": { + "placementId": "test-placement-no-cookie", + "customerId": "test-customer-no-cookie" + } + } + } + ], + "site": { + "id": "test-site-no-cookie", + "page": "https://example.com/no-cookie-test" + }, + "user": { + "id": "test-user-no-cookie" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + +} + +// TestORTB2HandlingWithExistingData tests generic ORTB2 data preservation using real-world payload +func TestORTB2HandlingWithExistingData(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Real-world ORTB2 payload with rich Contxtful data (anonymized) + requestJSON := `{ + "id": "46c96dbb-eb94-4661-8f82-17b026ee4fd8", + "test": 0, + "tmax": 1500, + "cur": ["USD"], + "imp": [ + { + "id": "273ad93d17f890a8", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "data": { + "adserver": { + "name": "gam", + "adslot": "/139271940/example>fr/example_site:header-2" + }, + "pbadslot": "/139271940/example>fr/example_site:header-2" + }, + "gpid": "/139271940/example>fr/example_site:header-2" + } + } + ], + "source": { + "ext": { + "schain": { + "ver": "1.0", + "complete": 1, + "nodes": [ + { + "asi": "contxtful.com", + "sid": "241212", + "hp": 1 + } + ] + } + } + }, + "ext": { + "prebid": { + "adServerCurrency": "USD" + } + }, + "site": { + "domain": "example.com", + "publisher": { + "domain": "example.com" + }, + "page": "https://example.com/", + "ext": { + "data": { + "documentLang": "fr-CA" + } + } + }, + "device": { + "w": 1728, + "h": 1117, + "dnt": 1, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", + "language": "fr", + "ext": { + "vpw": 1316, + "vph": 477 + }, + "sua": { + "source": 1, + "platform": { + "brand": "macOS" + }, + "browsers": [ + { + "brand": "Chromium", + "version": ["137"] + }, + { + "brand": "Not/A)Brand", + "version": ["24"] + } + ], + "mobile": 0 + } + }, + "user": { + "ext": { + "eids": [ + { + "source": "id5-sync.com", + "uids": [ + { + "id": "0", + "atype": 1, + "ext": { + "linkType": 0, + "pba": "QmkNifwqcX/XxmsANFijVw==" + } + } + ] + }, + { + "source": "pubcid.org", + "uids": [ + { + "id": "44609c87-de45-42d6-b024-2e159fc49df6", + "atype": 1 + } + ] + } + ] + }, + "data": [ + { + "name": "contxtful", + "ext": { + "sm": null, + "params": { + "ev": "v1", + "ci": "ABCD123456" + }, + "rx": { + "ReceptivityState": "NonReceptive", + "EclecticChinchilla": "false", + "score": "4", + "gptP": [ + { + "gpt": 1 + } + ], + "rand": 64.15681135773268 + } + }, + "segment": [ + { + "id": "NonReceptive" + } + ] + } + ] + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + // Add bidder parameters that would be injected by PBS + request.Imp[0].Ext = json.RawMessage(`{ + "bidder": { + "placementId": "test-placement-real", + "customerId": "ABCD123456" + }, + "data": { + "adserver": { + "name": "gam", + "adslot": "/139271940/example>fr/example_site:header-2" + }, + "pbadslot": "/139271940/example>fr/example_site:header-2" + }, + "gpid": "/139271940/example>fr/example_site:header-2" + }`) + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify ORTB2 data preservation + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + // Verify site data preservation (real-world structure) + site, ok := ortb2["site"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.site should be an object") + } + + if site["domain"] != "example.com" { + t.Error("ortb2.site.domain should be preserved") + } + + if site["page"] != "https://example.com/" { + t.Error("ortb2.site.page should be preserved") + } + + publisher, ok := site["publisher"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.site.publisher should be an object") + } + + if publisher["domain"] != "example.com" { + t.Error("ortb2.site.publisher.domain should be preserved") + } + + siteExt, ok := site["ext"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.site.ext should be an object") + } + + siteData, ok := siteExt["data"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.site.ext.data should be preserved") + } + + if siteData["documentLang"] != "fr-CA" { + t.Error("ortb2.site.ext.data.documentLang should be preserved") + } + + // Verify user data preservation and Contxtful data structure + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + // Verify user extensions with eids + userExt, ok := user["ext"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user.ext should be an object") + } + + eids, ok := userExt["eids"].([]interface{}) + if !ok || len(eids) < 2 { + t.Fatal("ortb2.user.ext.eids should be an array with multiple ID providers") + } + + // Check for ID5 and PubcID providers + var foundID5, foundPubcID bool + for _, eid := range eids { + eidObj, ok := eid.(map[string]interface{}) + if !ok { + continue + } + source := eidObj["source"].(string) + if source == "id5-sync.com" { + foundID5 = true + } + if source == "pubcid.org" { + foundPubcID = true + } + } + + if !foundID5 { + t.Error("ID5 external ID should be preserved") + } + if !foundPubcID { + t.Error("PubcID external ID should be preserved") + } + + // Verify Contxtful user data with rich structure + userData, ok := user["data"].([]interface{}) + if !ok { + t.Fatal("ortb2.user.data should be an array") + } + + if len(userData) != 1 { + t.Fatal("ortb2.user.data should contain exactly one Contxtful data segment") + } + + // Verify Contxtful data structure + contxtfulData, ok := userData[0].(map[string]interface{}) + if !ok { + t.Fatal("Contxtful user data should be an object") + } + + if contxtfulData["name"] != "contxtful" { + t.Error("User data should have name 'contxtful'") + } + + // Verify segments + segments, ok := contxtfulData["segment"].([]interface{}) + if !ok || len(segments) != 1 { + t.Fatal("Contxtful data should have segment array") + } + + segment := segments[0].(map[string]interface{}) + if segment["id"] != "NonReceptive" { + t.Error("Contxtful segment should be 'NonReceptive'") + } + + // Verify rich Contxtful extensions + contxtfulExt, ok := contxtfulData["ext"].(map[string]interface{}) + if !ok { + t.Fatal("Contxtful data should have ext object") + } + + // Check for params + params, ok := contxtfulExt["params"].(map[string]interface{}) + if !ok { + t.Fatal("Contxtful data should have params in ext") + } + + if params["ci"] != "ABCD123456" { + t.Error("Contxtful params should include correct customer ID (ABCD123456)") + } + + if params["ev"] != "v1" { + t.Error("Contxtful params should include correct version (v1)") + } + + // Verify receptivity data + rx, ok := contxtfulExt["rx"].(map[string]interface{}) + if !ok { + t.Fatal("Contxtful data should have rx (receptivity) object") + } + + if rx["ReceptivityState"] != "NonReceptive" { + t.Error("Receptivity state should be 'NonReceptive'") + } + + if rx["score"] != "4" { + t.Error("Receptivity score should be '4'") + } + + // Verify device data preservation (real-world structure) + device, ok := ortb2["device"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.device should be an object") + } + + if device["language"] != "fr" { + t.Error("ortb2.device.language should be preserved") + } + + if device["w"] != float64(1728) { + t.Error("ortb2.device.w should be preserved") + } + + if device["h"] != float64(1117) { + t.Error("ortb2.device.h should be preserved") + } + + // Verify SUA (Structured User Agent) data + sua, ok := device["sua"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.device.sua should be preserved") + } + + platform, ok := sua["platform"].(map[string]interface{}) + if !ok { + t.Fatal("SUA platform should be preserved") + } + + if platform["brand"] != "macOS" { + t.Error("SUA platform brand should be 'macOS'") + } + + browsers, ok := sua["browsers"].([]interface{}) + if !ok || len(browsers) < 2 { + t.Fatal("SUA browsers should be preserved") + } + + // Verify impression data preservation (without extensions) + imps, ok := ortb2["imp"].([]interface{}) + if !ok || len(imps) != 1 { + t.Fatal("ortb2.imp should be an array with one element") + } + + imp := imps[0].(map[string]interface{}) + + // Verify basic impression fields are preserved + if imp["id"] != "273ad93d17f890a8" { + t.Error("Impression ID should be preserved") + } + + if imp["secure"] != float64(1) { + t.Error("Impression secure flag should be preserved") + } + + // Verify banner object + banner, ok := imp["banner"].(map[string]interface{}) + if !ok { + t.Fatal("Impression banner should be preserved") + } + + if banner["topframe"] != float64(1) { + t.Error("Banner topframe should be preserved") + } + + // Note: Impression extensions (ext.data, ext.bidder) are correctly removed + // in the generic ORTB2 passthrough to avoid leaking bidder-specific data to the relay + + // Verify supply chain (schain) data + source, ok := ortb2["source"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.source should be preserved") + } + + sourceExt, ok := source["ext"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.source.ext should be preserved") + } + + schain, ok := sourceExt["schain"].(map[string]interface{}) + if !ok { + t.Fatal("Supply chain should be preserved") + } + + nodes, ok := schain["nodes"].([]interface{}) + if !ok || len(nodes) != 1 { + t.Fatal("Supply chain nodes should be preserved") + } + + node := nodes[0].(map[string]interface{}) + if node["asi"] != "contxtful.com" { + t.Error("Supply chain ASI should be 'contxtful.com'") + } +} + +// TestEventTrackingConfiguration tests that the adapter properly builds requests +// Note: Event tracking URLs are now injected by the Contxtful relay, not by PBS +func TestEventTrackingConfiguration(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create a video request to test that the adapter builds proper requests for relay event injection + requestJSON := `{ + "id": "test-request-events", + "imp": [ + { + "id": "test-imp-events", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "startdelay": 0, + "placement": 1, + "linearity": 1, + "skip": 0, + "playbackmethod": [1, 3], + "delivery": [1], + "api": [1, 2] + }, + "ext": { + "bidder": { + "placementId": "test-placement-events", + "customerId": "test-customer-events" + } + } + } + ], + "site": { + "id": "test-site-events", + "page": "https://example.com/event-test", + "domain": "example.com" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify the request structure is properly built for relay processing + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + // Verify request structure contains necessary data for relay event injection + bidRequests, ok := payload["bidRequests"].([]interface{}) + if !ok || len(bidRequests) != 1 { + t.Fatal("bidRequests should be an array with one element") + } + + bidRequest, ok := bidRequests[0].(map[string]interface{}) + if !ok { + t.Fatal("bidRequest should be an object") + } + + // Verify bidder code is present for relay event URL generation + if bidRequest["bidder"] != "contxtful" { + t.Error("Bidder code should be 'contxtful' for relay event tracking") + } + + // Verify bid ID is present for relay event URL generation + if bidRequest["bidId"] == nil { + t.Error("Bid ID should be present for relay event tracking") + } + + // Verify ORTB2 structure contains necessary data for relay + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + imp, ok := ortb2["imp"].([]interface{}) + if !ok || len(imp) != 1 { + t.Fatal("ortb2.imp should be an array with one element") + } + + impObj, ok := imp[0].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.imp[0] should be an object") + } + + // Verify impression ID is preserved for relay event tracking + if impObj["id"] != "test-imp-events" { + t.Error("Impression ID should be preserved for relay event tracking") + } + + // Verify the adapter preserves original media type (video stays video) + video, hasVideo := impObj["video"].(map[string]interface{}) + _, hasBanner := impObj["banner"].(map[string]interface{}) + + // Should have either video or banner (depending on original request) + if !hasVideo && !hasBanner { + t.Error("Impression should preserve original media type (video or banner)") + } + + // If video was in original request, it should be preserved + if hasVideo && video == nil { + t.Error("Video object should be preserved for relay processing") + } +} + +// TestCookieSyncEndpointGeneration tests cookie sync URL generation +func TestCookieSyncEndpointGeneration(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Note: User sync configuration is handled through PBS bidder-info files + // not through adapter config. This test verifies the adapter can be built + // successfully for sync scenarios. +} + +// TestBiddingProcessWithDifferentFormats tests bidding with various response formats +func TestBiddingProcessWithDifferentFormats(t *testing.T) { + tests := []struct { + name string + response string + expected bool + }{ + { + name: "Prebid.js format response", + response: `[{ + "cpm": 4.25, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-bid-1", + "mediaType": "banner", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "creativeId": "test-creative-1", + "netRevenue": true + }]`, + expected: true, + }, + { + name: "Trace format response (should be ignored)", + response: `{ + "trace": { + "request_id": "test-trace-1", + "debug": true, + "messages": ["Debug message"] + } + }`, + expected: false, + }, + } + + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(tt.response), + } + + // Create a dummy request for the response processing + requestJSON := `{ + "id": "test-request-formats", + "imp": [{ + "id": "test-imp-formats", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "test", "customerId": "test"}} + }] + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if tt.expected { + if len(errs) > 0 { + t.Errorf("Expected no errors, got: %v", errs) + } + if bids == nil || len(bids.Bids) == 0 { + t.Error("Expected bids to be returned") + } + } else { + // Trace responses should not generate bids + if bids != nil && len(bids.Bids) > 0 { + t.Error("Expected no bids for trace response") + } + } + }) + } +} + +// TestEventTrackingURLGeneration tests NURL and BURL event tracking URL generation +func TestEventTrackingURLGeneration(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + nurl := "https://monitoring.receptivity.io/v1/pbs/EVNT123/pbs-impression?b=contxtful-test-imp-events&a=EVNT123&bidder=contxtful&impId=test-imp-events&price=3.50&traceId=trace-abc-123&random=0.742856&domain=example.com&adRequestId=req-abc-456&w=728&h=90&f=b" + burl := "https://monitoring.receptivity.io/v1/pbs/EVNT123/pbs-billing?b=contxtful-test-imp-events&a=EVNT123&bidder=contxtful&impId=test-imp-events&price=3.50&traceId=trace-abc-123&random=0.742856&domain=example.com&adRequestId=req-abc-456&w=728&h=90&f=b" + + responseJSON := fmt.Sprintf(`[{ + "requestId": "test-imp-events", + "cpm": 3.50, + "currency": "USD", + "width": 728, + "height": 90, + "creativeId": "event-creative-1", + "adm": "<div>Event Tracking Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-abc-123", + "random": 0.742856, + "nurl": "%s", + "burl": "%s" + }]`, nurl, burl) + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + requestJSON := `{ + "id": "req-abc-456", + "imp": [{ + "id": "test-imp-events", + "banner": {"format": [{"w": 728, "h": 90}]}, + "ext": {"bidder": {"placementId": "event-test", "customerId": "EVNT123"}} + }], + "site": { + "domain": "example.com", + "page": "https://example.com/test-page" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + bidCount := 0 + if bids != nil { + bidCount = len(bids.Bids) + } + t.Fatalf("Expected 1 bid, got %d", bidCount) + } + + bid := bids.Bids[0] + + // Verify NURL (win notice URL) matches expected value exactly + if bid.Bid.NURL != nurl { + t.Errorf("NURL should be %s, got %s", nurl, bid.Bid.NURL) + } + + // Verify BURL (billing URL) matches expected value exactly + if bid.Bid.BURL != burl { + t.Errorf("BURL should be %s, got %s", burl, bid.Bid.BURL) + } +} + +// TestUserSyncWithBuyerUID tests user sync behavior when BuyerUID is present +func TestUserSyncWithBuyerUID(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + requestJSON := `{ + "id": "test-request-sync-existing", + "imp": [{ + "id": "test-imp-sync-existing", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "sync-test", "customerId": "SYNC123"}} + }], + "user": { + "buyeruid": "contxtful-v1-1234" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify payload includes user ID + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + buyerUID, ok := user["buyeruid"].(string) + if !ok || buyerUID == "" { + t.Error("User BuyerUID should be preserved in payload") + } + + if buyerUID != "contxtful-v1-1234" { + t.Errorf("Expected BuyerUID 'contxtful-v1-1234', got '%s'", buyerUID) + } +} + +// TestBuyerUIDFromPrebidMap tests reading UID from request.user.ext.prebid.buyeruids.contxtful and writing to ortb2.user.buyeruid +func TestBuyerUIDFromPrebidMap(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Test with UID in prebid buyeruids map (Priority 2 in extractUserIDForCookie) + testUID := "contxtful-v1-prebid-map-test-uid-456" + requestJSON := `{ + "id": "test-request-prebid-map", + "imp": [ + { + "id": "test-imp-prebid-map", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "placementId": "prebid-map-test", + "customerId": "PBMAP123" + } + } + } + ], + "site": { + "id": "test-site-prebid-map", + "page": "https://example.com/prebid-map-test" + }, + "user": { + "id": "test-user-prebid-map", + "ext": { + "prebid": { + "buyeruids": { + "contxtful": "` + testUID + `" + } + } + } + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify UID from prebid buyeruids map is written to ortb2.user.buyeruid + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + buyerUID, ok := user["buyeruid"].(string) + if !ok { + t.Fatal("ortb2.user.buyeruid should be present") + } + + if buyerUID != testUID { + t.Errorf("Expected UID from prebid buyeruids map '%s' to be written to ortb2.user.buyeruid, got '%s'", testUID, buyerUID) + } +} + +// TestNoCookieHeaders tests that cookie headers are never set (we only use ortb2.user.buyeruid) +func TestNoCookieHeaders(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + testCases := []struct { + name string + requestJSON string + description string + }{ + { + name: "With standard User.BuyerUID", + requestJSON: `{ + "id": "test-no-cookie-standard", + "imp": [{"id": "test-imp", "banner": {"format": [{"w": 300, "h": 250}]}, "ext": {"bidder": {"placementId": "test-placement", "customerId": "NOCOOKIE123"}}}], + "user": {"buyeruid": "standard-buyer-uid-123"} + }`, + description: "Standard BuyerUID should not generate cookie headers", + }, + { + name: "With prebid buyeruids map", + requestJSON: `{ + "id": "test-no-cookie-prebid", + "imp": [{"id": "test-imp", "banner": {"format": [{"w": 300, "h": 250}]}, "ext": {"bidder": {"placementId": "test-placement", "customerId": "NOCOOKIE123"}}}], + "user": {"ext": {"prebid": {"buyeruids": {"contxtful": "prebid-map-uid-456"}}}} + }`, + description: "Prebid buyeruids map should not generate cookie headers", + }, + { + name: "With no user data", + requestJSON: `{ + "id": "test-no-cookie-empty", + "imp": [{"id": "test-imp", "banner": {"format": [{"w": 300, "h": 250}]}, "ext": {"bidder": {"placementId": "test-placement", "customerId": "NOCOOKIE123"}}}] + }`, + description: "No user data should not generate cookie headers", + }, + { + name: "With Base64 encoded UID", + requestJSON: `{ + "id": "test-no-cookie-base64", + "imp": [{"id": "test-imp", "banner": {"format": [{"w": 300, "h": 250}]}, "ext": {"bidder": {"placementId": "test-placement", "customerId": "NOCOOKIE123"}}}], + "user": {"buyeruid": "contxtful-v1-1234"} + }`, + description: "Base64 encoded UID should not generate cookie headers", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(tc.requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // This is the single place where we verify no cookie headers are set + if len(requests) == 0 { + t.Fatal("No requests to check for cookie header") + } + cookieHeader := requests[0].Headers.Get("Cookie") + if cookieHeader != "" { + t.Errorf("Expected no Cookie header, got %s", cookieHeader) + } + }) + } +} + +// TestErrorHandling tests various error scenarios +func TestErrorHandling(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + tests := []struct { + name string + statusCode int + responseBody string + expectedErrors int + }{ + { + name: "HTTP 400 Error", + statusCode: 400, + responseBody: `{"error": "Bad Request"}`, + expectedErrors: 1, + }, + { + name: "HTTP 500 Error", + statusCode: 500, + responseBody: `{"error": "Internal Server Error"}`, + expectedErrors: 1, + }, + { + name: "Invalid JSON Response", + statusCode: 200, + responseBody: `{invalid json}`, + expectedErrors: 1, + }, + { + name: "Empty Response", + statusCode: 200, + responseBody: ``, + expectedErrors: 1, // Empty response should return error + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: tt.statusCode, + Body: []byte(tt.responseBody), + } + + requestJSON := `{ + "id": "test-request-error", + "imp": [{ + "id": "test-imp-error", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "error-test", "customerId": "ERROR123"}} + }] + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) != tt.expectedErrors { + t.Errorf("Expected %d errors, got %d: %v", tt.expectedErrors, len(errs), errs) + } + + // For error cases, we shouldn't get any bids + if tt.statusCode >= 400 && bids != nil && len(bids.Bids) > 0 { + t.Error("Should not return bids on HTTP error") + } + }) + } +} + +// Helper function to check if a string contains a substring +func contains(s, substr string) bool { + return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && + (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || + findSubstring(s, substr))) +} + +func findSubstring(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} + +// TestBase64PartnerUIDHandling tests the new Base64 encoded partner UID functionality +func TestBase64PartnerUIDHandling(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Test with Base64 encoded UID containing multiple partner UIDs + // This simulates what the relay would create after syncing with multiple partners + encodedUID := "contxtful-v1-eyJjdXN0b21lciI6IkNVU1RPTUVSMTIzIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtMTczNDU2Nzg5MC1hYmMxMjMiLCJzbWFhdG8iOiJzbWFhdG8tMTczNDU2Nzg5MC1kZWY0NTYiLCJpbWRzIjoiaW1kcy0xNzM0NTY3ODkwLWdoaTc4OSJ9LCJ2ZXJzaW9uIjoidjEifQ==" + + requestJSON := `{ + "id": "test-request-base64-uid", + "imp": [{ + "id": "test-imp-base64-uid", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "base64-test", "customerId": "CUSTOMER123"}} + }], + "user": { + "id": "test-user-base64", + "buyeruid": "` + encodedUID + `" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify the Base64 encoded UID is passed through correctly + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + buyerUID, ok := user["buyeruid"].(string) + if !ok || buyerUID == "" { + t.Error("User BuyerUID should be preserved in payload") + } + + if buyerUID != encodedUID { + t.Errorf("Expected encoded UID to be preserved, got '%s'", buyerUID) + } + + // Verify endpoint URL uses correct customer ID + expectedURL := "https://prebid.receptivity.io/v1/pbs/CUSTOMER123/bid" + if requests[0].Uri != expectedURL { + t.Errorf("Expected URL %s, got %s", expectedURL, requests[0].Uri) + } +} + +// TestBase64UIDVersioning tests different versions of Base64 encoded UIDs +func TestBase64UIDVersioning(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + testCases := []struct { + name string + version string + encodedUID string + expectError bool + }{ + { + name: "Version 1 UID", + version: "v1", + encodedUID: "contxtful-v1-eyJjdXN0b21lciI6IlRFU1RDVVNUIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCJ9LCJ2ZXJzaW9uIjoidjEifQ==", + expectError: false, + }, + { + name: "Version 1 UID (current)", + version: "v1", + encodedUID: "contxtful-v1-eyJjdXN0b21lciI6IlRFU1RDVVNUIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCIsInNtYWF0byI6InNtYWF0by10ZXN0In0sInZlcnNpb24iOiJ2MSJ9", + expectError: false, + }, + { + name: "Future Version v2 UID", + version: "v2", + encodedUID: "contxtful-v2-eyJjdXN0b21lciI6IlRFU1RDVVNUIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCIsInNtYWF0byI6InNtYWF0by10ZXN0In0sInZlcnNpb24iOiJ2MiJ9", + expectError: false, // PBS adapter should pass through any version + }, + { + name: "Future Version v3 UID", + version: "v3", + encodedUID: "contxtful-v3-eyJjdXN0b21lciI6IlRFU1RDVVNUIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCJ9LCJ2ZXJzaW9uIjoidjMifQ==", + expectError: false, // PBS adapter should pass through any version + }, + { + name: "Legacy Format (passthrough - no validation)", + version: "legacy", + encodedUID: "contxtful-TESTCUST-1734567890-abc123", + expectError: false, // Passthrough approach - no validation, relay handles format + }, + { + name: "Old Format with Customer (passthrough - no validation)", + version: "old", + encodedUID: "contxtful-v2-TESTCUST-eyJjdXN0b21lciI6IlRFU1RDVVNUIiwidGltZXN0YW1wIjoxNzM0NTY3ODkwMDAwLCJwYXJ0bmVycyI6eyJhbXgiOiJhbXgtdGVzdCJ9LCJ2ZXJzaW9uIjoidjIifQ==", + expectError: false, // Passthrough approach - no validation, relay handles format + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + requestJSON := `{ + "id": "test-request-versioning", + "imp": [{ + "id": "test-imp-versioning", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "version-test", "customerId": "TESTCUST"}} + }], + "user": { + "buyeruid": "` + tc.encodedUID + `" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if tc.expectError { + if len(errs) == 0 { + t.Errorf("Expected error for %s, but got none", tc.name) + } + return + } + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned unexpected errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify the versioned UID is passed through correctly + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + buyerUID, ok := user["buyeruid"].(string) + if !ok || buyerUID != tc.encodedUID { + t.Errorf("Expected UID %s to be preserved, got %s", tc.encodedUID, buyerUID) + } + }) + } +} + +// TestMultiPartnerUIDSize tests that the adapter handles large Base64 UIDs with many partners +func TestMultiPartnerUIDSize(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Simulate a large Base64 UID with 20 partners + // This tests the size limits and ensures the adapter can handle realistic scenarios + largeUID := "contxtful-v1-eyJjdXN0b21lciI6IkxBUkdFQ1VTVCIsInRpbWVzdGFtcCI6MTczNDU2Nzg5MDAwMCwicGFydG5lcnMiOnsiYW14IjoiYW14LTE3MzQ1Njc4OTAtYWJjMTIzIiwic21hYXRvIjoic21hYXRvLTE3MzQ1Njc4OTAtZGVmNDU2IiwiaW1kcyI6ImltZHMtMTczNDU2Nzg5MC1naGk3ODkiLCJwdWJtYXRpYyI6InB1Ym1hdGljLTE3MzQ1Njc4OTAtamtsMDEyIiwiaXgiOiJpeC0xNzM0NTY3ODkwLW1ubzM0NSIsIm9wZW54Ijoib3BlbngtMTczNDU2Nzg5MC1wcXI2NzgiLCJydWJpY29uIjoicnViaWNvbi0xNzM0NTY3ODkwLXN0dTkwMSIsImFwcG5leHVzIjoiYXBwbmV4dXMtMTczNDU2Nzg5MC12d3gyMzQiLCJjcml0ZW8iOiJjcml0ZW8tMTczNDU2Nzg5MC15ejU2NyIsImtpZG96Ijoia2lkb3otMTczNDU2Nzg5MC1hYmM4OTAiLCJtZ2lkIjoibWdpZC0xNzM0NTY3ODkwLWRlZjEyMyIsInVuaXJ1bHkiOiJ1bmlydWx5LTE3MzQ1Njc4OTAtZ2hpNDU2IiwidmlkYXp5IjoidmlkYXp5LTE3MzQ1Njc4OTAtamtsMTIzIiwiYWRmIjoiYWRmLTE3MzQ1Njc4OTAtbW5vNDU2IiwiYmVhY2hmcm9udCI6ImJlYWNoZnJvbnQtMTczNDU2Nzg5MC1wcXI3ODkiLCJlcGxhbm5pbmciOiJlcGxhbm5pbmctMTczNDU2Nzg5MC1zdHUwMTIiLCJncmlkIjoiZ3JpZC0xNzM0NTY3ODkwLXZ3eDM0NSIsImh1YXdlaWFkcyI6Imh1YXdlaWFkcy0xNzM0NTY3ODkwLXl6NTY3OCIsImltcHJvdmVkaWdpdGFsIjoiaW1wcm92ZWRpZ2l0YWwtMTczNDU2Nzg5MC1hYmM5MDEiLCJzbWFydGFkc2VydmVyIjoic21hcnRhZHNlcnZlci0xNzM0NTY3ODkwLWRlZjIzNCJ9LCJ2ZXJzaW9uIjoidjEifQ==" + + // Verify the UID is under cookie size limits (4KB) + if len(largeUID) > 4096 { + t.Errorf("Large UID size %d bytes exceeds cookie limit of 4096 bytes", len(largeUID)) + } + + requestJSON := `{ + "id": "test-request-large-uid", + "imp": [{ + "id": "test-imp-large-uid", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "large-uid-test", "customerId": "LARGECUST"}} + }], + "user": { + "buyeruid": "` + largeUID + `" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Verify the large UID is handled correctly in ortb2.user.buyeruid + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + user, ok := ortb2["user"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.user should be an object") + } + + buyerUID, ok := user["buyeruid"].(string) + if !ok || buyerUID != largeUID { + t.Error("Large UID should be preserved in ortb2.user.buyeruid") + } +} + +// TestPrebidJSEventTrackingURLGeneration tests NURL and BURL event tracking URL generation for Prebid.js format responses +func TestPrebidJSEventTrackingURLGeneration(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Test with Prebid.js format response (with tracking fields from relay) + nurl := "https://monitoring.receptivity.io/v1/pbs/PJSEVNT123/pbs-impression?b=contxtful-test-prebidjs-events&a=PJSEVNT123&bidder=contxtful&impId=test-prebidjs-events&price=2.75&traceId=prebidjs-trace-abc-789&random=0.654321&domain=prebidjs.example.com&adRequestId=prebidjs-req-456&w=300&h=250&f=b" + burl := "https://monitoring.receptivity.io/v1/pbs/PJSEVNT123/pbs-billing?b=contxtful-test-prebidjs-events&a=PJSEVNT123&bidder=contxtful&impId=test-prebidjs-events&price=2.75&traceId=prebidjs-trace-abc-789&random=0.654321&domain=prebidjs.example.com&adRequestId=prebidjs-req-456&w=300&h=250&f=b" + + responseJSON := fmt.Sprintf(`[{ + "cpm": 2.75, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-prebidjs-events", + "adm": "<div>Prebid.js Event Tracking Test Ad</div>", + "ttl": 300, + "creativeId": "prebidjs-creative-1", + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "prebidjs-trace-abc-789", + "random": 0.654321, + "nurl": "%s", + "burl": "%s" + }]`, nurl, burl) + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + requestJSON := `{ + "id": "prebidjs-req-456", + "imp": [{ + "id": "test-prebidjs-events", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "prebidjs-test", "customerId": "PJSEVNT123"}} + }], + "site": { + "domain": "prebidjs.example.com", + "page": "https://prebidjs.example.com/test-page" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + bidCount := 0 + if bids != nil { + bidCount = len(bids.Bids) + } + t.Fatalf("Expected 1 bid, got %d", bidCount) + } + + bid := bids.Bids[0] + + // Verify NURL (win notice URL) is set with enhanced parameters + if bid.Bid.NURL == "" { + t.Error("NURL should be set for Prebid.js response event tracking") + } else { + // Verify NURL contains all critical logging parameters + if !contains(bid.Bid.NURL, "pbs-impression") { + t.Error("NURL should contain t=win parameter") + } + if !contains(bid.Bid.NURL, "a=PJSEVNT123") { + t.Error("NURL should contain customer parameter (a=PJSEVNT123)") + } + if !contains(bid.Bid.NURL, "bidder=contxtful") { + t.Error("NURL should contain bidder=contxtful parameter") + } + if !contains(bid.Bid.NURL, "domain=prebidjs.example.com") { + t.Error("NURL should contain domain=prebidjs.example.com parameter") + } + if !contains(bid.Bid.NURL, "traceId=prebidjs-trace-abc-789") { + t.Error("NURL should contain traceId=prebidjs-trace-abc-789 parameter (real tracking data)") + } + if !contains(bid.Bid.NURL, "adRequestId=prebidjs-req-456") { + t.Error("NURL should contain adRequestId=prebidjs-req-456 parameter") + } + if !contains(bid.Bid.NURL, "random=0.654321") { + t.Error("NURL should contain random=0.654321 parameter (real tracking data)") + } + if !contains(bid.Bid.NURL, "impId=test-prebidjs-events") { + t.Error("NURL should contain impId=test-prebidjs-events parameter") + } + if !contains(bid.Bid.NURL, "price=2.75") { + t.Error("NURL should contain price=2.75 parameter") + } + if !contains(bid.Bid.NURL, "w=300") { + t.Error("NURL should contain w=300 parameter") + } + if !contains(bid.Bid.NURL, "h=250") { + t.Error("NURL should contain h=250 parameter") + } + } + + // Verify BURL (billing URL) is set with enhanced parameters + if bid.Bid.BURL == "" { + t.Error("BURL should be set for Prebid.js response event tracking") + } else { + // Verify BURL contains all critical logging parameters + if !contains(bid.Bid.BURL, "pbs-billing") { + t.Error("BURL should contain t=billing parameter") + } + if !contains(bid.Bid.BURL, "a=PJSEVNT123") { + t.Error("BURL should contain customer parameter (a=PJSEVNT123)") + } + if !contains(bid.Bid.BURL, "bidder=contxtful") { + t.Error("BURL should contain bidder=contxtful parameter") + } + if !contains(bid.Bid.BURL, "domain=prebidjs.example.com") { + t.Error("BURL should contain domain=prebidjs.example.com parameter") + } + if !contains(bid.Bid.BURL, "traceId=prebidjs-trace-abc-789") { + t.Error("BURL should contain traceId=prebidjs-trace-abc-789 parameter (real tracking data)") + } + if !contains(bid.Bid.BURL, "adRequestId=prebidjs-req-456") { + t.Error("BURL should contain adRequestId=prebidjs-req-456 parameter") + } + if !contains(bid.Bid.BURL, "random=0.654321") { + t.Error("BURL should contain random=0.654321 parameter (real tracking data)") + } + if !contains(bid.Bid.BURL, "impId=test-prebidjs-events") { + t.Error("BURL should contain impId=test-prebidjs-events parameter") + } + if !contains(bid.Bid.BURL, "price=2.75") { + t.Error("BURL should contain price=2.75 parameter") + } + if !contains(bid.Bid.BURL, "w=300") { + t.Error("BURL should contain w=300 parameter") + } + if !contains(bid.Bid.BURL, "h=250") { + t.Error("BURL should contain h=250 parameter") + } + } +} + +// TestPrebidJSHybridEventTrackingURLGeneration tests enhanced PrebidJS responses with tracking fields +func TestPrebidJSHybridEventTrackingURLGeneration(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Test with hybrid PrebidJS format response (has BOTH PrebidJS fields AND tracking fields) + responseJSON := `[{ + "cpm": 3.25, + "width": 728, + "height": 90, + "currency": "USD", + "requestId": "test-hybrid-events", + "adm": "<div>Hybrid PrebidJS Event Tracking Test Ad</div>", + "ttl": 300, + "creativeId": "hybrid-creative-1", + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "hybrid-abc-456-def", + "random": 0.9876543, + "nurl": "https://monitoring.receptivity.io/v1/pbs/HYBEVNT123/pbs-impression?b=contxtful-test-hybrid-events&a=HYBEVNT123&bidder=contxtful&impId=test-hybrid-events&price=3.25&traceId=hybrid-abc-456-def&random=0.987654&domain=hybrid.example.com&adRequestId=hybrid-req-789&w=728&h=90&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/HYBEVNT123/pbs-billing?b=contxtful-test-hybrid-events&a=HYBEVNT123&bidder=contxtful&impId=test-hybrid-events&price=3.25&traceId=hybrid-abc-456-def&random=0.987654&domain=hybrid.example.com&adRequestId=hybrid-req-789&w=728&h=90&f=b" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + requestJSON := `{ + "id": "hybrid-req-789", + "imp": [{ + "id": "test-hybrid-events", + "banner": {"format": [{"w": 728, "h": 90}]}, + "ext": {"bidder": {"placementId": "hybrid-test", "customerId": "HYBEVNT123"}} + }], + "site": { + "domain": "hybrid.example.com", + "page": "https://hybrid.example.com/test-page" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + bidCount := 0 + if bids != nil { + bidCount = len(bids.Bids) + } + t.Fatalf("Expected 1 bid, got %d", bidCount) + } + + bid := bids.Bids[0] + + // Verify NURL uses REAL tracking values (not fallbacks) + if bid.Bid.NURL == "" { + t.Error("NURL should be set for hybrid PrebidJS response event tracking") + } else { + // Verify NURL contains REAL tracking values (not fallbacks) + if !contains(bid.Bid.NURL, "traceId=hybrid-abc-456-def") { + t.Error("NURL should contain REAL traceId=hybrid-abc-456-def (not fallback 'unknown')") + } + if !contains(bid.Bid.NURL, "random=0.987654") { + t.Error("NURL should contain REAL random=0.987654 (not fallback '0.500000')") + } + if !contains(bid.Bid.NURL, "pbs-impression") { + t.Error("NURL should contain t=win parameter") + } + if !contains(bid.Bid.NURL, "a=HYBEVNT123") { + t.Error("NURL should contain customer parameter (a=HYBEVNT123)") + } + if !contains(bid.Bid.NURL, "domain=hybrid.example.com") { + t.Error("NURL should contain domain=hybrid.example.com parameter") + } + if !contains(bid.Bid.NURL, "price=3.25") { + t.Error("NURL should contain price=3.25 parameter") + } + } + + // Verify BURL uses REAL tracking values (not fallbacks) + if bid.Bid.BURL == "" { + t.Error("BURL should be set for hybrid PrebidJS response event tracking") + } else { + // Verify BURL contains REAL tracking values (not fallbacks) + if !contains(bid.Bid.BURL, "traceId=hybrid-abc-456-def") { + t.Error("BURL should contain REAL traceId=hybrid-abc-456-def (not fallback 'unknown')") + } + if !contains(bid.Bid.BURL, "random=0.987654") { + t.Error("BURL should contain REAL random=0.987654 (not fallback '0.500000')") + } + if !contains(bid.Bid.BURL, "pbs-billing") { + t.Error("BURL should contain t=billing parameter") + } + if !contains(bid.Bid.BURL, "a=HYBEVNT123") { + t.Error("BURL should contain customer parameter (a=HYBEVNT123)") + } + if !contains(bid.Bid.BURL, "domain=hybrid.example.com") { + t.Error("BURL should contain domain=hybrid.example.com parameter") + } + if !contains(bid.Bid.BURL, "price=3.25") { + t.Error("BURL should contain price=3.25 parameter") + } + } +} + +// TestResponseFormatDetectionPriority tests the priority and accuracy of response format detection +func TestResponseFormatDetectionPriority(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create a dummy request for testing + requestJSON := `{ + "id": "format-detection-test", + "imp": [{ + "id": "test-imp-format", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "format-test", "customerId": "FMTTEST"}} + }] + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + testCases := []struct { + name string + responseBody string + expectedFormat string + expectedBids int + expectedError bool + validateContent func(*testing.T, *adapters.BidderResponse) + }{ + { + name: "PrebidJS Format with Real Tracking", + responseBody: `[{ + "cpm": 2.50, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-prebidjs-pure", + "mediaType": "banner", + "adm": "<div>Pure PrebidJS Ad</div>", + "ttl": 300, + "creativeId": "pure-creative", + "netRevenue": true, + "traceId": "pure-detection-trace-xyz", + "random": 0.333777, + "nurl": "https://monitoring.receptivity.io/v1/pbs/FMTTEST/pbs-impression?b=contxtful-test-prebidjs-pure&a=FMTTEST&bidder=contxtful&impId=test-prebidjs-pure&price=2.50&traceId=pure-detection-trace-xyz&random=0.333777&domain=&adRequestId=format-detection-test&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/FMTTEST/pbs-billing?b=contxtful-test-prebidjs-pure&a=FMTTEST&bidder=contxtful&impId=test-prebidjs-pure&price=2.50&traceId=pure-detection-trace-xyz&random=0.333777&domain=&adRequestId=format-detection-test&w=300&h=250&f=b" + }]`, + expectedFormat: "PrebidJS", + expectedBids: 1, + expectedError: false, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + if len(bids.Bids) != 1 { + t.Errorf("Expected 1 bid, got %d", len(bids.Bids)) + return + } + // Should use real tracking values from response + nurl := bids.Bids[0].Bid.NURL + if !contains(nurl, "traceId=pure-detection-trace-xyz") { + t.Error("PrebidJS should use real traceId=pure-detection-trace-xyz") + } + if !contains(nurl, "random=0.333777") { + t.Error("PrebidJS should use real random=0.333777") + } + }, + }, + { + name: "Hybrid PrebidJS Format (with tracking fields) - Should be detected as PrebidJS", + responseBody: `[{ + "cpm": 3.75, + "width": 728, + "height": 90, + "currency": "USD", + "requestId": "test-hybrid-format", + "mediaType": "banner", + "adm": "<div>Hybrid PrebidJS Ad with Tracking</div>", + "ttl": 300, + "creativeId": "hybrid-creative", + "netRevenue": true, + "traceId": "hybrid-trace-123-abc", + "random": 0.8765432, + "nurl": "https://monitoring.receptivity.io/v1/pbs/FMTTEST/pbs-impression?b=contxtful-test-hybrid-format&a=FMTTEST&bidder=contxtful&impId=test-hybrid-format&price=3.75&traceId=hybrid-trace-123-abc&random=0.876543&domain=&adRequestId=format-detection-test&w=728&h=90&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/FMTTEST/pbs-billing?b=contxtful-test-hybrid-format&a=FMTTEST&bidder=contxtful&impId=test-hybrid-format&price=3.75&traceId=hybrid-trace-123-abc&random=0.876543&domain=&adRequestId=format-detection-test&w=728&h=90&f=b" + }]`, + expectedFormat: "PrebidJS", + expectedBids: 1, + expectedError: false, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + if len(bids.Bids) != 1 { + t.Errorf("Expected 1 bid, got %d", len(bids.Bids)) + return + } + // Should use REAL tracking values from response + nurl := bids.Bids[0].Bid.NURL + if !contains(nurl, "traceId=hybrid-trace-123-abc") { + t.Error("Hybrid PrebidJS should use REAL traceId=hybrid-trace-123-abc") + } + if !contains(nurl, "random=0.876543") { + t.Error("Hybrid PrebidJS should use REAL random=0.876543") + } + if contains(nurl, "traceId=unknown") { + t.Error("Hybrid PrebidJS should NOT use fallback traceId") + } + }, + }, + { + name: "Trace-only Response (no bids)", + responseBody: `[{ + "traceId": "trace-only-789-ghi", + "random": 0.9999999, + "bids": [] + }]`, + expectedFormat: "Trace", + expectedBids: 0, + expectedError: false, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + if len(bids.Bids) != 0 { + t.Errorf("Expected 0 bids for trace-only response, got %d", len(bids.Bids)) + } + }, + }, + { + name: "Malformed PrebidJS (missing required fields)", + responseBody: `[{ + "cpm": 1.50, + "currency": "USD" + }]`, + expectedFormat: "Error", + expectedBids: 0, + expectedError: false, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + // Should not generate bids for malformed response + if bids != nil && len(bids.Bids) > 0 { + t.Error("Should not generate bids for malformed PrebidJS response") + } + }, + }, + { + name: "Invalid JSON", + responseBody: `{invalid json syntax`, + expectedFormat: "Error", + expectedBids: 0, + expectedError: true, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + if bids != nil && len(bids.Bids) > 0 { + t.Error("Should not generate bids for invalid JSON") + } + }, + }, + { + name: "Empty Response", + responseBody: `[]`, + expectedFormat: "Error", + expectedBids: 0, + expectedError: true, + validateContent: func(t *testing.T, bids *adapters.BidderResponse) { + if bids != nil && len(bids.Bids) > 0 { + t.Error("Should not generate bids for empty response") + } + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(tc.responseBody), + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + // Validate error expectations + if tc.expectedError { + if len(errs) == 0 { + t.Errorf("Expected errors for %s, but got none", tc.name) + } + } else { + if len(errs) > 0 { + t.Errorf("Unexpected errors for %s: %v", tc.name, errs) + } + } + + // Validate bid count + actualBids := 0 + if bids != nil { + actualBids = len(bids.Bids) + } + if actualBids != tc.expectedBids { + t.Errorf("Expected %d bids, got %d", tc.expectedBids, actualBids) + } + + // Run custom validation + if tc.validateContent != nil && bids != nil { + tc.validateContent(t, bids) + } + }) + } +} + +// TestTrackingValuePropagation tests that tracking values correctly flow from responses to event URLs +func TestTrackingValuePropagation(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Test with comprehensive tracking data + testCases := []struct { + name string + responseBody string + requestID string + domain string + customer string + expectedValues map[string]string + }{ + { + name: "Hybrid PrebidJS with Tracking", + responseBody: `[{ + "cpm": 3.25, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "tracking-imp-2", + "mediaType": "banner", + "adm": "<div>Hybrid Tracking Ad</div>", + "ttl": 300, + "creativeId": "hybrid-tracking-creative", + "netRevenue": true, + "traceId": "hybrid-trace-def-456", + "random": 0.123456789, + "nurl": "https://monitoring.receptivity.io/v1/pbs/HYBRID123/pbs-impression?b=contxtful-tracking-imp-2&a=HYBRID123&bidder=contxtful&impId=tracking-imp-2&price=3.25&traceId=hybrid-trace-def-456&random=0.123457&domain=hybrid.tracking.com&adRequestId=hybrid-tracking-request-456&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/HYBRID123/pbs-billing?b=contxtful-tracking-imp-2&a=HYBRID123&bidder=contxtful&impId=tracking-imp-2&price=3.25&traceId=hybrid-trace-def-456&random=0.123457&domain=hybrid.tracking.com&adRequestId=hybrid-tracking-request-456&w=300&h=250&f=b" + }]`, + requestID: "hybrid-tracking-request-456", + domain: "hybrid.tracking.com", + customer: "HYBRID123", + expectedValues: map[string]string{ + "traceId": "hybrid-trace-def-456", + "random": "0.123457", // Note: formatted with 6 decimal places + "adRequestId": "hybrid-tracking-request-456", + "domain": "hybrid.tracking.com", + "a": "HYBRID123", + "price": "3.25", + "w": "300", + "h": "250", + "impId": "tracking-imp-2", + }, + }, + { + name: "PrebidJS with Real Tracking Data", + responseBody: `[{ + "cpm": 1.85, + "width": 320, + "height": 50, + "currency": "USD", + "requestId": "tracking-imp-3", + "mediaType": "banner", + "adm": "<div>Pure PrebidJS Ad</div>", + "ttl": 300, + "creativeId": "pure-creative", + "netRevenue": true, + "traceId": "pure-trace-ghi-789", + "random": 0.444555, + "nurl": "https://monitoring.receptivity.io/v1/pbs/PURE123/pbs-impression?b=contxtful-tracking-imp-3&a=PURE123&bidder=contxtful&impId=tracking-imp-3&price=1.85&traceId=pure-trace-ghi-789&random=0.444555&domain=pure.tracking.com&adRequestId=pure-tracking-request-789&w=320&h=50&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/PURE123/pbs-billing?b=contxtful-tracking-imp-3&a=PURE123&bidder=contxtful&impId=tracking-imp-3&price=1.85&traceId=pure-trace-ghi-789&random=0.444555&domain=pure.tracking.com&adRequestId=pure-tracking-request-789&w=320&h=50&f=b" + }]`, + requestID: "pure-tracking-request-789", + domain: "pure.tracking.com", + customer: "PURE123", + expectedValues: map[string]string{ + "traceId": "pure-trace-ghi-789", // Real tracking data + "random": "0.444555", // Real tracking data + "adRequestId": "pure-tracking-request-789", + "domain": "pure.tracking.com", + "a": "PURE123", + "price": "1.85", + "w": "320", + "h": "50", + "impId": "tracking-imp-3", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + requestJSON := fmt.Sprintf(`{ + "id": "%s", + "imp": [{ + "id": "%s", + "banner": {"format": [{"w": %s, "h": %s}]}, + "ext": {"bidder": {"placementId": "tracking-test", "customerId": "%s"}} + }], + "site": { + "domain": "%s", + "page": "https://%s/test-page" + } + }`, tc.requestID, tc.expectedValues["impId"], tc.expectedValues["w"], tc.expectedValues["h"], tc.customer, tc.domain, tc.domain) + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(tc.responseBody), + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bids.Bids)) + } + + bid := bids.Bids[0] + + // Validate NURL contains all expected tracking values + if bid.Bid.NURL == "" { + t.Fatal("NURL should be set") + } + + for key, expectedValue := range tc.expectedValues { + expectedParam := fmt.Sprintf("%s=%s", key, expectedValue) + if !contains(bid.Bid.NURL, expectedParam) { + t.Errorf("NURL should contain %s", expectedParam) + } + } + + // Validate BURL contains all expected tracking values + if bid.Bid.BURL == "" { + t.Fatal("BURL should be set") + } + + for key, expectedValue := range tc.expectedValues { + expectedParam := fmt.Sprintf("%s=%s", key, expectedValue) + if !contains(bid.Bid.BURL, expectedParam) { + t.Errorf("BURL should contain %s", expectedParam) + } + } + + // Verify event type differences + if !contains(bid.Bid.NURL, "pbs-impression") { + t.Error("NURL should contain t=win") + } + if !contains(bid.Bid.BURL, "pbs-billing") { + t.Error("BURL should contain t=billing") + } + }) + } +} + +// TestResponseFormatEdgeCases tests edge cases and error scenarios in response format detection +func TestResponseFormatEdgeCases(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + requestJSON := `{ + "id": "edge-case-test", + "imp": [{ + "id": "edge-case-imp", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "edge-test", "customerId": "EDGE123"}} + }] + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + testCases := []struct { + name string + responseBody string + statusCode int + expectedBids int + expectedErrors int + description string + }{ + { + name: "Partial PrebidJS (missing ad field)", + responseBody: `[{ + "cpm": 2.50, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "partial-prebidjs" + }]`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 1, + description: "Should fail when required PrebidJS fields are missing", + }, + { + name: "Empty bids array in relay format", + responseBody: `[{ + "traceId": "empty-relay-trace", + "random": 0.5, + "bids": [] + }]`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 0, + description: "Should handle empty bids array gracefully", + }, + { + name: "Mixed valid and invalid bids in PrebidJS", + responseBody: `[ + { + "cpm": 2.50, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "valid-bid", + "mediaType": "banner", + "adm": "<div>Valid Ad</div>", + "ttl": 300, + "creativeId": "valid-creative", + "netRevenue": true + }, + { + "cpm": 0, + "requestId": "invalid-bid" + } + ]`, + statusCode: 200, + expectedBids: 1, + expectedErrors: 0, + description: "Should process valid bids and ignore invalid ones", + }, + { + name: "Relay format with tracking but no bids array", + responseBody: `[{ + "traceId": "no-bids-trace-123", + "random": 0.777777 + }]`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 0, + description: "Should handle tracking data without bids array gracefully (trace data)", + }, + { + name: "HTTP Error Response", + responseBody: `{"error": "Internal Server Error"}`, + statusCode: 500, + expectedBids: 0, + expectedErrors: 1, + description: "Should handle HTTP errors gracefully", + }, + { + name: "Very Large Response", + responseBody: func() string { + // Generate a response with many bids to test size handling + var bids []string + for i := 0; i < 100; i++ { + bid := fmt.Sprintf(`{ + "cpm": %d.25, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "large-bid-%d", + "mediaType": "banner", + "adm": "<div>Large Response Bid %d</div>", + "ttl": 300, + "creativeId": "large-creative-%d", + "netRevenue": true + }`, i+1, i, i, i) + bids = append(bids, bid) + } + return "[" + strings.Join(bids, ",") + "]" + }(), + statusCode: 200, + expectedBids: 100, + expectedErrors: 0, + description: "Should handle large responses with many bids", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: tc.statusCode, + Body: []byte(tc.responseBody), + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + // Validate error count + if len(errs) != tc.expectedErrors { + t.Errorf("Expected %d errors, got %d: %v", tc.expectedErrors, len(errs), errs) + } + + // Validate bid count + actualBids := 0 + if bids != nil { + actualBids = len(bids.Bids) + } + if actualBids != tc.expectedBids { + t.Errorf("Expected %d bids, got %d", tc.expectedBids, actualBids) + } + + }) + } +} + +// TestEventURLGeneration tests comprehensive event URL parameter inclusion +func TestEventURLGeneration(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create request with comprehensive tracking parameters + requestJSON := `{ + "id": "event-url-test", + "imp": [{ + "id": "test-imp-event", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": { + "bidder": { + "placementId": "12345", + "customerId": "EVNTTEST123" + } + } + }], + "site": {"domain": "example.com"}, + "ext": { + "trace": "event-trace-789", + "prebid": { + "adRequestId": "req-abc-123" + } + } + }` + + var request openrtb2.BidRequest + if err := jsonutil.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal request: %v", err) + } + + // Test Case 1: PrebidJS response with comprehensive tracking + responseJSON := `[{ + "requestId": "test-imp-event", + "cpm": 1.25, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "test-creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "event-trace-789", + "random": 0.123456789, + "nurl": "https://monitoring.receptivity.io/v1/pbs/EVNTTEST123/pbs-impression?b=contxtful-test-imp-event&a=EVNTTEST123&bidder=contxtful&impId=test-imp-event&price=1.25&traceId=event-trace-789&random=0.123457&domain=example.com&adRequestId=event-url-test&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/EVNTTEST123/pbs-billing?b=contxtful-test-imp-event&a=EVNTTEST123&bidder=contxtful&impId=test-imp-event&price=1.25&traceId=event-trace-789&random=0.123457&domain=example.com&adRequestId=event-url-test&w=300&h=250&f=b" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + bidResponse, errs := bidder.MakeBids(&request, nil, response) + + if len(errs) != 0 { + t.Fatalf("Expected no errors, got %v", errs) + } + + if len(bidResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidResponse.Bids)) + } + + bid := bidResponse.Bids[0] + + // Validate NURL contains all required parameters + expectedParams := []string{ + "domain=example.com", + "traceId=event-trace-789", + "adRequestId=event-url-test", // Uses bid request ID as fallback + "random=0.123457", // Truncated in URL format + "bidder=contxtful", + "a=EVNTTEST123", // Customer ID parameter + "impId=test-imp-event", // Impression ID parameter + "f=b", + "price=1.25", // Relay format provides price in bid data + } + + for _, param := range expectedParams { + if !strings.Contains(bid.Bid.NURL, param) { + t.Errorf("NURL missing parameter: %s\nActual NURL: %s", param, bid.Bid.NURL) + } + } + + // Validate BURL contains billing parameters + expectedBillingParams := []string{ + "f=b", + "bidder=contxtful", + "a=EVNTTEST123", // Customer ID parameter + } + + for _, param := range expectedBillingParams { + if !strings.Contains(bid.Bid.BURL, param) { + t.Errorf("BURL missing parameter: %s\nActual BURL: %s", param, bid.Bid.BURL) + } + } +} + +// TestBidRejectionScenarios tests various scenarios that should result in bid rejection +func TestBidRejectionScenarios(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + requestJSON := `{ + "id": "rejection-test", + "imp": [{ + "id": "test-imp-reject", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": { + "bidder": { + "placementId": "12345", + "customerId": "REJECTTEST123" + } + } + }] + }` + + var request openrtb2.BidRequest + if err := jsonutil.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal request: %v", err) + } + + testCases := []struct { + name string + responseBody string + statusCode int + expectedBids int + expectedErrors int + description string + }{ + { + name: "Relay response with no bids array", + responseBody: `[{ + "traceId": "no-bids-trace", + "random": 0.5 + }]`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 0, + description: "Should handle tracking-only response gracefully", + }, + { + name: "Relay response with empty bids array", + responseBody: `[{ + "traceId": "empty-bids-trace", + "random": 0.5, + "bids": [] + }]`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 0, + description: "Should handle empty bids array gracefully", + }, + { + name: "Invalid JSON response", + responseBody: `{invalid json}`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 1, + description: "Should handle malformed JSON with error", + }, + { + name: "HTTP error response", + responseBody: `{"error": "Server error"}`, + statusCode: 500, + expectedBids: 0, + expectedErrors: 1, + description: "Should handle HTTP errors properly", + }, + { + name: "PrebidJS response with missing required fields", + responseBody: `{ + "id": "test", + "seatbid": [{ + "bid": [{ + "id": "bid1" + }] + }] + }`, + statusCode: 200, + expectedBids: 0, + expectedErrors: 1, + description: "Should reject bids missing required fields", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: tc.statusCode, + Body: []byte(tc.responseBody), + } + + bidResponse, errs := bidder.MakeBids(&request, nil, response) + + actualBids := 0 + if bidResponse != nil && bidResponse.Bids != nil { + actualBids = len(bidResponse.Bids) + } + + if actualBids != tc.expectedBids { + t.Errorf("Expected %d bids, got %d", tc.expectedBids, actualBids) + } + + if len(errs) != tc.expectedErrors { + t.Errorf("Expected %d errors, got %d: %v", tc.expectedErrors, len(errs), errs) + } + }) + } +} + +// TestBidExtensionsRegression ensures that essential bid extensions are present in relay responses +// This test prevents regression of the bid extension creation logic that was accidentally removed during refactoring +func TestBidExtensionsRegression(t *testing.T) { + // Create mock adapter + server := config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"} + mockAdapter, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://relay.example.com/v1/pbs/{{.CustomerId}}/bid", + }, server) + assert.NoError(t, buildErr) + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-bid-extensions", + Test: 1, // Enable test mode + Imp: []openrtb2.Imp{{ + ID: "test-imp-extensions", + Ext: json.RawMessage(`{ + "bidder": { + "customerId": "EXTTEST123" + } + }`), + }}, + Site: &openrtb2.Site{ + Domain: "test.extension.com", + Page: "https://test.extension.com", + }, + User: &openrtb2.User{ + BuyerUID: "contxtful-v1-eyJjdXN0b21lciI6IkVYVFRFU1QxMjMiLCJ0aW1lc3RhbXAiOjE3MzQ1Njc4OTAwMDAsInBhcnRuZXJzIjp7ImFteCI6ImFteC10ZXN0In0sInZlcnNpb24iOiJ2MSJ9", + }, + } + + // Create mock response data - PREBIDJS FORMAT with bid extensions + mockRelayResponse := `[{ + "requestId": "test-imp-extensions", + "cpm": 2.85, + "adm": "<div>Test ad for extension validation</div>", + "width": 300, + "height": 250, + "creativeId": "extension-creative-456", + "netRevenue": true, + "currency": "USD", + "mediaType": "banner", + "bidderCode": "contxtful", + "nurl": "https://monitoring.receptivity.io/v1/pbs/EXTTEST123/pbs-impression?b=contxtful-test-imp-extensions&a=EXTTEST123&bidder=contxtful&impId=test-imp-extensions&price=2.85&traceId=extension-test-trace-123&random=0.789123&domain=extensions.example.com&adRequestId=extension-test-request&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/EXTTEST123/pbs-billing?b=contxtful-test-imp-extensions&a=EXTTEST123&bidder=contxtful&impId=test-imp-extensions&price=2.85&traceId=extension-test-trace-123&random=0.789123&domain=extensions.example.com&adRequestId=extension-test-request&w=300&h=250&f=b", + "ext": { + "contxtful": { + "segment": "premium", + "dealId": "DEAL-123", + "customData": "test-value" + } + } + }]` + + responseData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(mockRelayResponse), + } + + // Call MakeBids + bidderResponse, errs := mockAdapter.MakeBids(request, nil, responseData) + + // Verify no errors + assert.Empty(t, errs, "Expected no errors") + assert.NotNil(t, bidderResponse, "Expected bidder response") + + // Verify bid was created + assert.Len(t, bidderResponse.Bids, 1, "Expected exactly 1 bid") + + bid := bidderResponse.Bids[0].Bid + + // CRITICAL REGRESSION CHECK: Verify bid extensions are present and copied as-is + assert.NotNil(t, bid.Ext, "BID EXTENSIONS MISSING! Contxtful ext should be copied as-is") + + // Parse bid extensions + var bidExt map[string]interface{} + err := json.Unmarshal(bid.Ext, &bidExt) + assert.NoError(t, err, "Failed to parse bid extensions JSON") + + // Verify contxtful ext data is copied as-is from the original response + assert.Contains(t, bidExt, "contxtful", "Missing contxtful extensions - should be copied as-is") + + contxtfulExt, hasContxtfulExt := bidExt["contxtful"].(map[string]interface{}) + assert.True(t, hasContxtfulExt, "contxtful extensions should be present") + + // Verify specific contxtful ext fields that were in the mock response + assert.Equal(t, "premium", contxtfulExt["segment"], "segment should be copied as-is") + assert.Equal(t, "DEAL-123", contxtfulExt["dealId"], "dealId should be copied as-is") + assert.Equal(t, "test-value", contxtfulExt["customData"], "customData should be copied as-is") + + // Verify essential PBS bid extensions are present (production-level fields only) + // Note: contxtfulDebug has been removed for production - only core PBS fields remain + + // Verify NURL/BURL are set (these should be generated by generateEventURLs) + assert.NotEmpty(t, bid.NURL, "NURL should be generated for event tracking") + assert.NotEmpty(t, bid.BURL, "BURL should be generated for event tracking") + assert.Contains(t, bid.NURL, "pbs-impression", "NURL should contain win tracking parameter") + assert.Contains(t, bid.BURL, "pbs-billing", "BURL should contain billing tracking parameter") +} + +// TestS2SBidderConfigExtraction tests extraction of rich bidder config data from S2S payloads +func TestS2SBidderConfigExtraction(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Real S2S payload with rich bidder config data (based on user's example) + requestJSON := `{ + "id": "s2s-bidder-config-test", + "test": 1, + "tmax": 30000, + "imp": [ + { + "id": "/19968336/header-bid-tag-0", + "banner": { + "topframe": 1, + "format": [ + {"w": 300, "h": 250}, + {"w": 300, "h": 600} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "p101152", + "customerId": "ABCD123456" + } + } + } + ], + "site": { + "domain": "localhost:3000", + "publisher": { + "domain": "localhost:3000", + "id": "1" + }, + "page": "http://localhost:3000/view?link=test", + "ext": { + "data": { + "documentLang": "en" + } + } + }, + "device": { + "w": 1728, + "h": 1117, + "dnt": 1, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "language": "fr", + "ext": { + "vpw": 1645, + "vph": 411 + } + }, + "ext": { + "prebid": { + "auctiontimestamp": 1751152008051, + "bidderconfig": [ + { + "bidders": ["contxtful"], + "config": { + "ortb2": { + "user": { + "data": [ + { + "name": "contxtful", + "ext": { + "rx": { + "ReceptivityState": "Receptive", + "EclecticChinchilla": "true", + "score": "90", + "gptP": [ + { + "gpt": 1 + } + ], + "rand": 66.70383102561092 + }, + "sm": "0fa9d2f7-96a2-497a-83c7-e4f14ee4b580", + "params": { + "ev": "v1", + "ci": "ABCD123456" + } + }, + "segment": [ + { + "id": "Receptive" + } + ] + } + ] + } + } + } + } + ], + "debug": true + } + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requests, errs := bidder.MakeRequests(&request, &adapters.ExtraRequestInfo{}) + + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request, got %d", len(requests)) + } + + // Parse the request payload to verify bidder config data was extracted and merged + var payload map[string]interface{} + if err := json.Unmarshal(requests[0].Body, &payload); err != nil { + t.Fatalf("Failed to unmarshal request payload: %v", err) + } + + // Verify the config uses bidder config version and customer (not impression params) + config, ok := payload["config"].(map[string]interface{}) + if !ok { + t.Fatal("Config should be an object") + } + + contxtfulConfig, ok := config["contxtful"].(map[string]interface{}) + if !ok { + t.Fatal("Contxtful config should be an object") + } + + // Verify version from bidder config (not default) + if contxtfulConfig["version"] != "v1" { + t.Errorf("Expected version 'v1' from bidder config, got %v", contxtfulConfig["version"]) + } + + // Verify customer from bidder config (priority over impression params) + expectedCustomer := "ABCD123456" // From bidder config params.ci + if contxtfulConfig["customer"] != expectedCustomer { + t.Errorf("Expected customer '%s' from bidder config, got %v", expectedCustomer, contxtfulConfig["customer"]) + } + + // Verify endpoint URL uses bidder config customer ID + expectedURL := "https://prebid.receptivity.io/v1/pbs/ABCD123456/bid" + if requests[0].Uri != expectedURL { + t.Errorf("Expected URL %s (with bidder config customer), got %s", expectedURL, requests[0].Uri) + } + + // Verify ortb2 contains original data (simple passthrough - no complex merging) + ortb2, ok := payload["ortb2"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2 should be an object") + } + + // Verify basic ortb2 structure is preserved as-is + if ortb2["test"] != float64(1) { + t.Error("ortb2.test should be preserved as-is") + } + + if ortb2["tmax"] != float64(30000) { + t.Error("ortb2.tmax should be preserved as-is") + } + + // Verify site data is preserved as-is + site, ok := ortb2["site"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.site should be preserved as-is") + } + + if site["domain"] != "localhost:3000" { + t.Error("ortb2.site.domain should be preserved as-is") + } + + // Verify device data is preserved as-is + device, ok := ortb2["device"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.device should be preserved as-is") + } + + if device["language"] != "fr" { + t.Error("ortb2.device.language should be preserved as-is") + } + + // Verify bidder config data is available in ext.prebid.bidderconfig (original location) + // The relay can extract rich data from here directly - no need for adapter to merge it + ext, ok := ortb2["ext"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.ext should be preserved as-is") + } + + prebid, ok := ext["prebid"].(map[string]interface{}) + if !ok { + t.Fatal("ortb2.ext.prebid should be preserved as-is") + } + + bidderConfig, ok := prebid["bidderconfig"].([]interface{}) + if !ok || len(bidderConfig) == 0 { + t.Fatal("ortb2.ext.prebid.bidderconfig should be preserved for relay processing") + } +} + +// TestCustomerIDFromURIExtraction tests that customer ID is correctly extracted from request URI +func TestCustomerIDFromURIExtraction(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create response with bids + responseJSON := `[{ + "requestId": "test-imp-uri-extraction", + "cpm": 2.25, + "adm": "<div>URI Extraction Test Ad</div>", + "width": 728, + "height": 90, + "creativeId": "uri-extraction-creative", + "netRevenue": true, + "currency": "USD", + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "uri-extraction-test-123", + "random": 0.777888, + "nurl": "https://monitoring.receptivity.io/v1/pbs/URITEST123/pbs-impression?b=contxtful-test-imp-uri-extraction&a=URITEST123&bidder=contxtful&impId=test-imp-uri-extraction&price=2.25&traceId=uri-extraction-test-123&random=0.777888&domain=uri-extraction-test.com&adRequestId=uri-extraction-test&w=728&h=90&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/URITEST123/pbs-billing?b=contxtful-test-imp-uri-extraction&a=URITEST123&bidder=contxtful&impId=test-imp-uri-extraction&price=2.25&traceId=uri-extraction-test-123&random=0.777888&domain=uri-extraction-test.com&adRequestId=uri-extraction-test&w=728&h=90&f=b" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + // Create request WITHOUT bidder config and WITHOUT valid impression params + // (simulating cleaned up request data) + requestJSON := `{ + "id": "uri-extraction-test", + "imp": [{ + "id": "test-imp-uri-extraction", + "banner": {"format": [{"w": 728, "h": 90}]}, + "ext": {} + }], + "site": { + "domain": "uri-extraction-test.com", + "page": "https://uri-extraction-test.com/test" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + // Create requestData with URI containing customer ID (this is what MakeRequests creates) + requestData := &adapters.RequestData{ + Method: "POST", + Uri: "https://prebid.receptivity.io/v1/pbs/URITEST123/bid", // Customer ID in URI + Body: []byte(`{"test": "data"}`), + } + + // MakeBids should successfully extract customer ID from URI and generate event URLs + bids, errs := bidder.MakeBids(&request, requestData, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned unexpected errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + bidCount := 0 + if bids != nil { + bidCount = len(bids.Bids) + } + t.Fatalf("Expected 1 bid, got %d", bidCount) + } + + bid := bids.Bids[0] + + // Verify event URLs are generated with correct customer ID from URI + if bid.Bid.NURL == "" { + t.Error("NURL should be generated when customer ID is available from URI") + } else { + // Should contain customer ID from URI + if !contains(bid.Bid.NURL, "/v1/pbs/URITEST123/pbs-impression") { + t.Error("NURL should contain customer ID extracted from URI (URITEST123)") + } + + // Should contain tracking data + if !contains(bid.Bid.NURL, "traceId=uri-extraction-test-123") { + t.Error("NURL should contain tracking data from response") + } + } + + // Verify BURL is also generated correctly + if bid.Bid.BURL == "" { + t.Error("BURL should be generated when customer ID is available from URI") + } else { + // Should contain customer ID from URI + if !contains(bid.Bid.BURL, "/v1/pbs/URITEST123/pbs-billing") { + t.Error("BURL should contain customer ID extracted from URI (URITEST123)") + } + } +} + +// TestEventURLGenerationNoDoubleSlash tests that event URLs never have double slashes with URI extraction +func TestEventURLGenerationNoDoubleSlash(t *testing.T) { + // Test with trailing slash on monitoring endpoint + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + testCases := []struct { + name string + requestURI string + expectedCustomer string + }{ + { + name: "Production endpoint", + requestURI: "https://prebid.receptivity.io/v1/pbs/PRODCUST123/bid", + expectedCustomer: "PRODCUST123", + }, + { + name: "Development endpoint", + requestURI: "https://prebid.receptivity.io/v1/pbs/DEVCUST456/bid", + expectedCustomer: "DEVCUST456", + }, + { + name: "Monitoring endpoint with trailing slash", + requestURI: "https://prebid.receptivity.io/v1/pbs/SLASHTEST789/bid", + expectedCustomer: "SLASHTEST789", + }, + { + name: "Localhost development", + requestURI: "http://localhost:6789/v1/pbs/LOCALTEST999/bid", + expectedCustomer: "LOCALTEST999", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Update adapter's monitoring endpoint for this test + + responseJSON := fmt.Sprintf(`[{ + "requestId": "test-imp-no-double-slash", + "cpm": 3.75, + "adm": "<div>No Double Slash Test Ad</div>", + "width": 300, + "height": 250, + "creativeId": "no-double-slash-creative", + "netRevenue": true, + "currency": "USD", + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "no-double-slash-test-456", + "random": 0.123456, + "nurl": "%s/v1/pbs/%s/pbs-impression?b=contxtful-test-imp-no-double-slash&a=%s&bidder=contxtful&impId=test-imp-no-double-slash&price=3.75&traceId=no-double-slash-test-456&random=0.123456&domain=test.nodoubleSlash.com&adRequestId=no-double-slash-test&w=300&h=250&f=b", + "burl": "%s/v1/pbs/%s/pbs-billing?b=contxtful-test-imp-no-double-slash&a=%s&bidder=contxtful&impId=test-imp-no-double-slash&price=3.75&traceId=no-double-slash-test-456&random=0.123456&domain=test.nodoubleSlash.com&adRequestId=no-double-slash-test&w=300&h=250&f=b" + }]`, "https://monitoring.com/", tc.expectedCustomer, tc.expectedCustomer, "https://monitoring.com/", tc.expectedCustomer, tc.expectedCustomer) + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + requestJSON := `{ + "id": "no-double-slash-test", + "imp": [{ + "id": "test-imp-no-double-slash", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {} + }], + "site": { + "domain": "test.nodoubleSlash.com", + "page": "https://test.nodoubleSlash.com/test" + } + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: tc.requestURI, + Body: []byte(`{"test": "data"}`), + } + + bids, errs := bidder.MakeBids(&request, requestData, response) + + if len(errs) > 0 { + t.Fatalf("MakeBids returned unexpected errors: %v", errs) + } + + if bids == nil || len(bids.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bids.Bids)) + } + + bid := bids.Bids[0] + + // Critical test: Verify NO double slashes anywhere in URLs + if contains(bid.Bid.NURL, "//pbs-impression") { + t.Errorf("NURL contains double slash: %s", bid.Bid.NURL) + } + + if contains(bid.Bid.BURL, "//pbs-billing") { + t.Errorf("BURL contains double slash: %s", bid.Bid.BURL) + } + + // Verify correct customer ID is used in URLs + expectedNURLPattern := fmt.Sprintf("/v1/pbs/%s/pbs-impression", tc.expectedCustomer) + if !contains(bid.Bid.NURL, expectedNURLPattern) { + t.Errorf("NURL should contain %s, got: %s", expectedNURLPattern, bid.Bid.NURL) + } + + expectedBURLPattern := fmt.Sprintf("/v1/pbs/%s/pbs-billing", tc.expectedCustomer) + if !contains(bid.Bid.BURL, expectedBURLPattern) { + t.Errorf("BURL should contain %s, got: %s", expectedBURLPattern, bid.Bid.BURL) + } + + // Verify customer parameter is correct + expectedCustomerParam := fmt.Sprintf("a=%s", tc.expectedCustomer) + if !contains(bid.Bid.NURL, expectedCustomerParam) { + t.Errorf("NURL should contain %s", expectedCustomerParam) + } + }) + } +} + +// TestNURLBURLFromPrebidJSResponse tests NURL/BURL extraction from PrebidJS format responses +func TestNURLBURLFromPrebidJSResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with NURL/BURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "nurl": "https://example.com/win?price=${AUCTION_PRICE}", + "burl": "https://example.com/billing?price=${AUCTION_PRICE}" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify NURL is passed through from response + expectedNURL := "https://example.com/win?price=${AUCTION_PRICE}" + if bid.NURL != expectedNURL { + t.Errorf("NURL should be %s, got %s", expectedNURL, bid.NURL) + } + + // Verify BURL is passed through from response + expectedBURL := "https://example.com/billing?price=${AUCTION_PRICE}" + if bid.BURL != expectedBURL { + t.Errorf("BURL should be %s, got %s", expectedBURL, bid.BURL) + } +} + +// TestNURLBURLFromContxtfulRelayResponse tests NURL/BURL extraction from ContxtfulRelay format responses +func TestNURLBURLFromContxtfulRelayResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 728, H: 90}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "test.com", + }, + } + + // Mock response with PrebidJS format including NURL/BURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 1.75, + "adm": "<div>Relay Ad</div>", + "width": 728, + "height": 90, + "creativeId": "creative-456", + "netRevenue": true, + "currency": "USD", + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-456", + "random": 0.654321, + "nurl": "https://relay.example.com/notify?win=1", + "burl": "https://relay.example.com/bill?event=1" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify NURL is passed through from response + expectedNURL := "https://relay.example.com/notify?win=1" + if bid.NURL != expectedNURL { + t.Errorf("NURL should be %s, got %s", expectedNURL, bid.NURL) + } + + // Verify BURL is passed through from response + expectedBURL := "https://relay.example.com/bill?event=1" + if bid.BURL != expectedBURL { + t.Errorf("BURL should be %s, got %s", expectedBURL, bid.BURL) + } +} + +// TestNURLBURLWithoutResponseURLs tests that event URLs are generated correctly when response has no NURL/BURL +func TestNURLBURLWithoutResponseURLs(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response without NURL/BURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456 + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify NURL/BURL are not set when not provided in response + if bid.NURL != "" { + t.Error("NURL should be empty when no response NURL is provided") + } + if bid.BURL != "" { + t.Error("BURL should be empty when no response BURL is provided") + } +} + +// TestNURLBURLURLEncoding tests that special characters in response URLs are properly encoded +func TestNURLBURLURLEncoding(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with URLs containing special characters that need encoding + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "nurl": "https://example.com/win?price=${AUCTION_PRICE}&data={\"test\":\"value\"}&special=a+b c&hash#fragment", + "burl": "https://example.com/billing?price=${AUCTION_PRICE}&data={\"test\":\"value\"}&special=a+b c&hash#fragment" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify the complex URL is passed through as-is (no encoding) + expectedNURL := "https://example.com/win?price=${AUCTION_PRICE}&data={\"test\":\"value\"}&special=a+b c&hash#fragment" + if bid.NURL != expectedNURL { + t.Errorf("NURL should be %s, got %s", expectedNURL, bid.NURL) + } + + expectedBURL := "https://example.com/billing?price=${AUCTION_PRICE}&data={\"test\":\"value\"}&special=a+b c&hash#fragment" + if bid.BURL != expectedBURL { + t.Errorf("BURL should be %s, got %s", expectedBURL, bid.BURL) + } +} + +// TestNURLBURLPartialResponse tests handling when only one of NURL or BURL is present +func TestNURLBURLPartialResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with only NURL (no BURL) + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "nurl": "https://example.com/win?price=${AUCTION_PRICE}" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify NURL is passed through from response + expectedNURL := "https://example.com/win?price=${AUCTION_PRICE}" + if bid.NURL != expectedNURL { + t.Errorf("NURL should be %s, got %s", expectedNURL, bid.NURL) + } + + // Verify BURL is empty (not provided in response) + if bid.BURL != "" { + t.Errorf("BURL should be empty when not provided in response, got %s", bid.BURL) + } +} + +// TestNURLBURLEmptyStrings tests handling of empty string values in response +func TestNURLBURLEmptyStrings(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with empty string values for NURL/BURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "nurl": "", + "burl": "" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify URLs don't contain 'r' parameter for empty strings + if strings.Contains(bid.NURL, "&r=") { + t.Error("NURL should not contain r parameter when response NURL is empty") + } + if strings.Contains(bid.BURL, "&r=") { + t.Error("BURL should not contain r parameter when response BURL is empty") + } +} + +// TestNURLBURLNotPresentInRelayResponse tests that NURL/BURL are not set when not present in ContxtfulRelay response +func TestNURLBURLNotPresentInRelayResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 728, H: 90}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "test.com", + }, + } + + // Mock response with PrebidJS format WITHOUT NURL/BURL fields + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 1.75, + "adm": "<div>Relay Ad</div>", + "width": 728, + "height": 90, + "creativeId": "creative-456", + "netRevenue": true, + "currency": "USD", + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-456", + "random": 0.654321 + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify NURL is not set when not provided in response + if bid.NURL != "" { + t.Errorf("NURL should be empty when not present in relay response, got %s", bid.NURL) + } + + // Verify BURL is not set when not provided in response + if bid.BURL != "" { + t.Errorf("BURL should be empty when not present in relay response, got %s", bid.BURL) + } +} + +// TestLURLFromPrebidJSResponse tests LURL (Loss URL) extraction from PrebidJS format responses +func TestLURLFromPrebidJSResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with LURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "lurl": "https://example.com/loss?price=${AUCTION_PRICE}&reason=${AUCTION_LOSS}" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify LURL is passed through from response + expectedLURL := "https://example.com/loss?price=${AUCTION_PRICE}&reason=${AUCTION_LOSS}" + if bid.LURL != expectedLURL { + t.Errorf("LURL should be %s, got %s", expectedLURL, bid.LURL) + } +} + +// TestLURLWithoutResponseURL tests that LURL is not set when not provided in response +func TestLURLWithoutResponseURL(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response without LURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456 + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify LURL is not set when not provided in response + if bid.LURL != "" { + t.Errorf("LURL should be empty when not provided in response, got %s", bid.LURL) + } +} + +// TestLURLEmptyString tests handling of empty string values for LURL in response +func TestLURLEmptyString(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create test request + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + {W: 300, H: 250}, + }, + }, + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "test-placement", + "customerId": "test-customer" + } + }`), + }, + }, + Site: &openrtb2.Site{ + Domain: "example.com", + }, + } + + // Mock response with empty string value for LURL + responseBody := `[{ + "requestId": "test-imp-id", + "cpm": 2.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "trace-123", + "random": 0.123456, + "lurl": "" + }]` + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseBody), + } + + // Make the request to get request data + requestData, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + if len(errs) > 0 { + t.Fatalf("MakeRequests returned errors: %v", errs) + } + + // Process the response + bidderResponse, errs := bidder.MakeBids(request, requestData[0], response) + if len(errs) > 0 { + t.Fatalf("MakeBids returned errors: %v", errs) + } + + // Verify we got a bid + if len(bidderResponse.Bids) != 1 { + t.Fatalf("Expected 1 bid, got %d", len(bidderResponse.Bids)) + } + + bid := bidderResponse.Bids[0].Bid + + // Verify LURL is empty when provided as empty string + if bid.LURL != "" { + t.Errorf("LURL should be empty when provided as empty string, got %s", bid.LURL) + } +} + +// TestBuildEndpointURL tests the buildEndpointURL function with various scenarios +func TestBuildEndpointURL(t *testing.T) { + // Create adapter instance for testing + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + contxtfulAdapter := bidder.(*adapter) + + tests := []struct { + name string + request *openrtb2.BidRequest + expectedURL string + expectedValidPlacements []string + expectedCustomerID string + expectedErrors int + description string + }{ + { + name: "Valid request with single impression", + request: &openrtb2.BidRequest{ + ID: "test-request-1", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "placement-123", + "customerId": "customer-456" + } + }`), + }, + }, + }, + expectedURL: "https://prebid.receptivity.io/v1/pbs/customer-456/bid", + expectedValidPlacements: []string{"placement-123"}, + expectedCustomerID: "customer-456", + expectedErrors: 0, + description: "Should successfully build endpoint URL with valid impression data", + }, + { + name: "Valid request with multiple impressions", + request: &openrtb2.BidRequest{ + ID: "test-request-2", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "placement-123", + "customerId": "customer-456" + } + }`), + }, + { + ID: "test-imp-2", + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "placement-789", + "customerId": "customer-456" + } + }`), + }, + }, + }, + expectedURL: "https://prebid.receptivity.io/v1/pbs/customer-456/bid", + expectedValidPlacements: []string{"placement-123", "placement-789"}, + expectedCustomerID: "customer-456", + expectedErrors: 0, + description: "Should handle multiple impressions with same customer ID", + }, + { + name: "Request with invalid impression extension", + request: &openrtb2.BidRequest{ + ID: "test-request-3", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Ext: json.RawMessage(`{invalid json}`), + }, + }, + }, + expectedURL: "", + expectedValidPlacements: []string{}, + expectedCustomerID: "", + expectedErrors: 1, + description: "Should return error for invalid impression extension JSON", + }, + { + name: "Request with no impressions", + request: &openrtb2.BidRequest{ + ID: "test-request-4", + Imp: []openrtb2.Imp{}, + }, + expectedURL: "https://prebid.receptivity.io/v1/pbs//bid", + expectedValidPlacements: []string{}, + expectedCustomerID: "", + expectedErrors: 0, + description: "Should handle empty impressions gracefully", + }, + { + name: "Request with mixed valid and invalid impressions", + request: &openrtb2.BidRequest{ + ID: "test-request-5", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "placement-123", + "customerId": "customer-456" + } + }`), + }, + { + ID: "test-imp-2", + Ext: json.RawMessage(`{invalid json}`), + }, + }, + }, + expectedURL: "", + expectedValidPlacements: []string{"placement-123"}, + expectedCustomerID: "customer-456", + expectedErrors: 1, + description: "Should return error when any impression validation fails", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + url, validPlacements, customerID, errs := contxtfulAdapter.buildEndpointURL(tt.request) + + // Check URL + if url != tt.expectedURL { + t.Errorf("Expected URL %q, got %q", tt.expectedURL, url) + } + + // Check valid placements + if len(validPlacements) != len(tt.expectedValidPlacements) { + t.Errorf("Expected %d valid placements, got %d", len(tt.expectedValidPlacements), len(validPlacements)) + } else { + for i, expected := range tt.expectedValidPlacements { + if i < len(validPlacements) && validPlacements[i] != expected { + t.Errorf("Expected placement[%d] %q, got %q", i, expected, validPlacements[i]) + } + } + } + + // Check customer ID + if customerID != tt.expectedCustomerID { + t.Errorf("Expected customer ID %q, got %q", tt.expectedCustomerID, customerID) + } + + // Check errors + if len(errs) != tt.expectedErrors { + t.Errorf("Expected %d errors, got %d: %v", tt.expectedErrors, len(errs), errs) + } + }) + } +} + +// TestBuildEndpointURLMacroFailure tests buildEndpointURL when macro resolution fails +func TestBuildEndpointURLMacroFailure(t *testing.T) { + // Create adapter with invalid template that will cause macro resolution to fail + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.InvalidMacro}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + contxtfulAdapter := bidder.(*adapter) + + request := &openrtb2.BidRequest{ + ID: "test-macro-failure", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Ext: json.RawMessage(`{ + "bidder": { + "placementId": "placement-123", + "customerId": "customer-456" + } + }`), + }, + }, + } + + url, validPlacements, customerID, errs := contxtfulAdapter.buildEndpointURL(request) + + // Should fail at macro resolution step + if url != "" { + t.Errorf("Expected empty URL when macro resolution fails, got %q", url) + } + + // Should still return valid placements and customer ID from validation step + if len(validPlacements) != 1 || validPlacements[0] != "placement-123" { + t.Errorf("Expected valid placements to be returned even when macro fails, got %v", validPlacements) + } + + if customerID != "customer-456" { + t.Errorf("Expected customer ID to be returned even when macro fails, got %q", customerID) + } + + // Should have at least one error from macro resolution + if len(errs) == 0 { + t.Error("Expected at least one error when macro resolution fails") + } +} + +// TestPrebidJSValidationErrors tests the validation of PrebidJS responses for missing required fields +func TestPrebidJSValidationErrors(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderContxtful, config.Adapter{ + Endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + // Create a test request + requestJSON := `{ + "id": "test-request-validation", + "imp": [{ + "id": "test-imp-validation", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": {"bidder": {"placementId": "validation-test", "customerId": "VALIDATION123"}} + }] + }` + + var request openrtb2.BidRequest + if err := json.Unmarshal([]byte(requestJSON), &request); err != nil { + t.Fatalf("Failed to unmarshal test request: %v", err) + } + + testCases := []struct { + name string + responseBody string + expectedErrors int + expectedBids int + errorMessages []string + }{ + { + name: "Missing AdM", + responseBody: `[{ + "requestId": "test-imp-validation", + "cpm": 1.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "mediaType": "banner", + "ttl": 300, + "netRevenue": true, + "bidderCode": "contxtful", + "nurl": "https://example.com/nurl", + "burl": "https://example.com/burl" + }]`, + expectedErrors: 1, + expectedBids: 0, + errorMessages: []string{"bid has no ad markup"}, + }, + { + name: "Empty AdM", + responseBody: `[{ + "requestId": "test-imp-validation", + "cpm": 1.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "", + "mediaType": "banner", + "ttl": 300, + "netRevenue": true, + "bidderCode": "contxtful", + "nurl": "https://example.com/nurl", + "burl": "https://example.com/burl" + }]`, + expectedErrors: 1, + expectedBids: 0, + errorMessages: []string{"bid has no ad markup"}, + }, + { + name: "Valid bid with all required fields", + responseBody: `[{ + "requestId": "test-imp-validation", + "cpm": 1.50, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "creative-123", + "adm": "<div>Valid ad markup</div>", + "mediaType": "banner", + "ttl": 300, + "netRevenue": true, + "bidderCode": "contxtful", + "nurl": "https://example.com/nurl", + "burl": "https://example.com/burl" + }]`, + expectedErrors: 0, + expectedBids: 1, + errorMessages: []string{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(tc.responseBody), + } + + bids, errs := bidder.MakeBids(&request, nil, response) + + // Check error count + if len(errs) != tc.expectedErrors { + t.Errorf("Expected %d errors, got %d: %v", tc.expectedErrors, len(errs), errs) + } + + // Check bid count + actualBids := 0 + if bids != nil { + actualBids = len(bids.Bids) + } + if actualBids != tc.expectedBids { + t.Errorf("Expected %d bids, got %d", tc.expectedBids, actualBids) + } + + // Check specific error messages + if len(tc.errorMessages) > 0 { + errorStrings := make([]string, len(errs)) + for i, err := range errs { + errorStrings[i] = err.Error() + } + + for _, expectedMsg := range tc.errorMessages { + found := false + for _, actualMsg := range errorStrings { + if strings.Contains(actualMsg, expectedMsg) { + found = true + break + } + } + if !found { + t.Errorf("Expected error message containing '%s', but not found in: %v", expectedMsg, errorStrings) + } + } + } + + // For valid cases, verify bid fields are populated correctly + if tc.expectedBids > 0 && tc.expectedErrors == 0 && bids != nil && len(bids.Bids) > 0 { + bid := bids.Bids[0] + assert.NotEmpty(t, bid.Bid.AdM, "AdM should be populated for valid bids") + assert.NotEqual(t, openrtb_ext.BidType(""), bid.BidType, "BidType should be populated for valid bids") + } + }) + } +} diff --git a/adapters/contxtful/contxtfultest/exemplary/multiple-impressions.json b/adapters/contxtful/contxtfultest/exemplary/multiple-impressions.json new file mode 100644 index 0000000000..59e1b375ea --- /dev/null +++ b/adapters/contxtful/contxtfultest/exemplary/multiple-impressions.json @@ -0,0 +1,332 @@ +{ + "mockBidRequest": { + "id": "test-request-multi", + "imp": [ + { + "id": "test-imp-header", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "header-leaderboard" + } + } + }, + { + "id": "test-imp-sidebar", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "sidebar-display" + } + } + }, + { + "id": "test-imp-footer", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "mobile-footer" + } + } + } + ], + "site": { + "id": "multi-demo-site", + "domain": "multi.example.com", + "page": "https://multi.example.com/article", + "publisher": { + "id": "multi-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15", + "ip": "192.0.2.3", + "language": "en", + "dnt": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/DEMO123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-header", + "bidder": "contxtful", + "params": { + "placementId": "header-leaderboard" + } + }, + { + "bidId": "test-imp-sidebar", + "bidder": "contxtful", + "params": { + "placementId": "sidebar-display" + } + }, + { + "bidId": "test-imp-footer", + "bidder": "contxtful", + "params": { + "placementId": "mobile-footer" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "DEMO123", + "version": "v1" + } + }, + + "ortb2": { + "device": { + "dnt": 0, + "ip": "192.0.2.3", + "language": "en", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15" + }, + "id": "test-request-multi", + "imp": [ + { + "banner": { + "format": [ + { + "h": 90, + "w": 728 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "header-leaderboard" + } + }, + "id": "test-imp-header" + }, + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + }, + { + "h": 600, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "sidebar-display" + } + }, + "id": "test-imp-sidebar" + }, + { + "banner": { + "format": [ + { + "h": 50, + "w": 320 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "mobile-footer" + } + }, + "id": "test-imp-footer" + } + ], + "site": { + "domain": "multi.example.com", + "id": "multi-demo-site", + "page": "https://multi.example.com/article", + "publisher": { + "id": "multi-publisher" + } + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-header", "test-imp-sidebar", "test-imp-footer"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 3.25, + "width": 728, + "height": 90, + "currency": "USD", + "requestId": "test-imp-header", + "adm": "<div style=\"width:728px;height:90px;background:#e3f2fd;text-align:center;line-height:90px;\">Contxtful Header Ad</div>", + "ttl": 300, + "creativeId": "header-creative-789", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-header&a=DEMO123&bidder=contxtful&impId=test-imp-header&price=3.25&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=728&h=90&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-header&a=DEMO123&bidder=contxtful&impId=test-imp-header&price=3.25&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=728&h=90&f=b", + "ext": { + "contxtful": { + "placement": "header", + "reseller": "premium-partner" + } + } + }, + { + "cpm": 2.80, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-imp-sidebar", + "adm": "<div style=\"width:300px;height:250px;background:#f3e5f5;text-align:center;line-height:250px;\">Contxtful Sidebar Ad</div>", + "ttl": 300, + "creativeId": "sidebar-creative-101", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-sidebar&a=DEMO123&bidder=contxtful&impId=test-imp-sidebar&price=2.80&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-sidebar&a=DEMO123&bidder=contxtful&impId=test-imp-sidebar&price=2.80&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=300&h=250&f=b", + "ext": { + "contxtful": { + "placement": "sidebar", + "format": "display" + } + } + }, + { + "cpm": 1.50, + "width": 320, + "height": 50, + "currency": "USD", + "requestId": "test-imp-footer", + "adm": "<div style=\"width:320px;height:50px;background:#e8f5e8;text-align:center;line-height:50px;\">Contxtful Mobile Ad</div>", + "ttl": 300, + "creativeId": "footer-creative-202", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-footer&a=DEMO123&bidder=contxtful&impId=test-imp-footer&price=1.50&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=320&h=50&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-footer&a=DEMO123&bidder=contxtful&impId=test-imp-footer&price=1.50&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=320&h=50&f=b", + "ext": { + "contxtful": { + "placement": "footer", + "device": "mobile" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-header", + "impid": "test-imp-header", + "price": 3.25, + "adm": "<div style=\"width:728px;height:90px;background:#e3f2fd;text-align:center;line-height:90px;\">Contxtful Header Ad</div>", + "w": 728, + "h": 90, + "crid": "header-creative-789", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-header&a=DEMO123&bidder=contxtful&impId=test-imp-header&price=3.25&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=728&h=90&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-header&a=DEMO123&bidder=contxtful&impId=test-imp-header&price=3.25&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=728&h=90&f=b", + "ext": { + "contxtful": { + "placement": "header", + "reseller": "premium-partner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "contxtful-test-imp-sidebar", + "impid": "test-imp-sidebar", + "price": 2.80, + "adm": "<div style=\"width:300px;height:250px;background:#f3e5f5;text-align:center;line-height:250px;\">Contxtful Sidebar Ad</div>", + "w": 300, + "h": 250, + "crid": "sidebar-creative-101", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-sidebar&a=DEMO123&bidder=contxtful&impId=test-imp-sidebar&price=2.80&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-sidebar&a=DEMO123&bidder=contxtful&impId=test-imp-sidebar&price=2.80&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=300&h=250&f=b", + "ext": { + "contxtful": { + "placement": "sidebar", + "format": "display" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "contxtful-test-imp-footer", + "impid": "test-imp-footer", + "price": 1.50, + "adm": "<div style=\"width:320px;height:50px;background:#e8f5e8;text-align:center;line-height:50px;\">Contxtful Mobile Ad</div>", + "w": 320, + "h": 50, + "crid": "footer-creative-202", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-footer&a=DEMO123&bidder=contxtful&impId=test-imp-footer&price=1.50&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=320&h=50&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-footer&a=DEMO123&bidder=contxtful&impId=test-imp-footer&price=1.50&traceId=&random=0.000000&domain=multi.example.com&adRequestId=test-request-multi&w=320&h=50&f=b", + "ext": { + "contxtful": { + "placement": "footer", + "device": "mobile" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/exemplary/simple-banner.json b/adapters/contxtful/contxtfultest/exemplary/simple-banner.json new file mode 100644 index 0000000000..b1354cd461 --- /dev/null +++ b/adapters/contxtful/contxtfultest/exemplary/simple-banner.json @@ -0,0 +1,168 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "banner-placement-1" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/DEMO123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-banner", + "bidder": "contxtful", + "params": { + "placementId": "banner-placement-1" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "DEMO123", + "version": "v1" + } + }, + + "ortb2": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "banner-placement-1" + } + }, + "id": "test-imp-banner" + } + ], + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 2.50, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-imp-banner", + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Contxtful Demo Ad</div>", + "ttl": 300, + "creativeId": "demo-creative-123", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-banner", + "impid": "test-imp-banner", + "price": 2.50, + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Contxtful Demo Ad</div>", + "w": 300, + "h": 250, + "crid": "demo-creative-123", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/exemplary/simple-native.json b/adapters/contxtful/contxtfultest/exemplary/simple-native.json new file mode 100644 index 0000000000..d4f3c4aa1f --- /dev/null +++ b/adapters/contxtful/contxtfultest/exemplary/simple-native.json @@ -0,0 +1,158 @@ +{ + "mockBidRequest": { + "id": "test-request-native", + "imp": [ + { + "id": "test-imp-native", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":150,\"h\":50}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":90}}]}" + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "native-placement-1" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/DEMO123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-native", + "bidder": "contxtful", + "params": { + "placementId": "native-placement-1" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "DEMO123", + "version": "v1" + } + }, + + "ortb2": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-native", + "imp": [ + { + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":150,\"h\":50}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":90}}]}" + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "native-placement-1" + } + }, + "id": "test-imp-native" + } + ], + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-native"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 1.75, + "width": 1, + "height": 1, + "currency": "USD", + "requestId": "test-imp-native", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Contxtful Native Ad\"}},{\"id\":2,\"img\":{\"url\":\"https://example.com/native-img.jpg\",\"w\":150,\"h\":50}},{\"id\":3,\"data\":{\"value\":\"Experience the best native advertising with Contxtful technology.\"}}],\"link\":{\"url\":\"https://example.com/click\"}}", + "ttl": 300, + "creativeId": "demo-native-creative-456", + "netRevenue": true, + "mediaType": "native", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-native&a=DEMO123&bidder=contxtful&impId=test-imp-native&price=1.75&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-native&w=1&h=1&f=n", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-native&a=DEMO123&bidder=contxtful&impId=test-imp-native&price=1.75&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-native&w=1&h=1&f=n", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-native", + "impid": "test-imp-native", + "price": 1.75, + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Contxtful Native Ad\"}},{\"id\":2,\"img\":{\"url\":\"https://example.com/native-img.jpg\",\"w\":150,\"h\":50}},{\"id\":3,\"data\":{\"value\":\"Experience the best native advertising with Contxtful technology.\"}}],\"link\":{\"url\":\"https://example.com/click\"}}", + "w": 1, + "h": 1, + "crid": "demo-native-creative-456", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-native&a=DEMO123&bidder=contxtful&impId=test-imp-native&price=1.75&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-native&w=1&h=1&f=n", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-native&a=DEMO123&bidder=contxtful&impId=test-imp-native&price=1.75&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-native&w=1&h=1&f=n", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/exemplary/video.json b/adapters/contxtful/contxtfultest/exemplary/video.json new file mode 100644 index 0000000000..76d46e32a1 --- /dev/null +++ b/adapters/contxtful/contxtfultest/exemplary/video.json @@ -0,0 +1,176 @@ +{ + "mockBidRequest": { + "id": "test-request-video", + "imp": [ + { + "id": "test-imp-video", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "startdelay": 0, + "placement": 1, + "linearity": 1, + "skip": 0, + "playbackmethod": [1, 3], + "delivery": [1], + "api": [1, 2] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "video-placement-1" + } + } + } + ], + "site": { + "id": "demo-video-site", + "domain": "video.example.com", + "page": "https://video.example.com/player", + "publisher": { + "id": "video-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "ip": "192.0.2.2", + "language": "en", + "dnt": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/DEMO123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-video", + "bidder": "contxtful", + "params": { + "placementId": "video-placement-1" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "DEMO123", + "version": "v1" + } + }, + + "ortb2": { + "device": { + "dnt": 0, + "ip": "192.0.2.2", + "language": "en", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" + }, + "id": "test-request-video", + "imp": [ + { + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "video-placement-1" + } + }, + "id": "test-imp-video", + "video": { + "api": [1, 2], + "delivery": [1], + "h": 480, + "linearity": 1, + "maxduration": 30, + "mimes": ["video/mp4"], + "minduration": 5, + "placement": 1, + "playbackmethod": [1, 3], + "protocols": [2, 3, 5, 6], + "skip": 0, + "startdelay": 0, + "w": 640 + } + } + ], + "site": { + "domain": "video.example.com", + "id": "demo-video-site", + "page": "https://video.example.com/player", + "publisher": { + "id": "video-publisher" + } + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-video"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 4.75, + "width": 640, + "height": 480, + "currency": "USD", + "requestId": "test-imp-video", + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"3.0\"><Ad id=\"demo-video-ad\"><InLine><AdSystem>Contxtful</AdSystem><AdTitle>Demo Video Ad</AdTitle><Creatives><Creative><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"640\" height=\"480\">https://demo.contxtful.com/video.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "ttl": 300, + "creativeId": "demo-video-creative-456", + "netRevenue": true, + "mediaType": "video", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-video&a=DEMO123&bidder=contxtful&impId=test-imp-video&price=4.75&traceId=&random=0.000000&domain=video.example.com&adRequestId=test-request-video&w=640&h=480&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-video&a=DEMO123&bidder=contxtful&impId=test-imp-video&price=4.75&traceId=&random=0.000000&domain=video.example.com&adRequestId=test-request-video&w=640&h=480&f=b", + "ext": { + "contxtful": { + "mediaType": "video", + "vast": "inline" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-video", + "impid": "test-imp-video", + "price": 4.75, + "adm": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><VAST version=\"3.0\"><Ad id=\"demo-video-ad\"><InLine><AdSystem>Contxtful</AdSystem><AdTitle>Demo Video Ad</AdTitle><Creatives><Creative><Linear><Duration>00:00:15</Duration><MediaFiles><MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"640\" height=\"480\">https://demo.contxtful.com/video.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "w": 640, + "h": 480, + "crid": "demo-video-creative-456", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-video&a=DEMO123&bidder=contxtful&impId=test-imp-video&price=4.75&traceId=&random=0.000000&domain=video.example.com&adRequestId=test-request-video&w=640&h=480&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-video&a=DEMO123&bidder=contxtful&impId=test-imp-video&price=4.75&traceId=&random=0.000000&domain=video.example.com&adRequestId=test-request-video&w=640&h=480&f=b", + "ext": { + "contxtful": { + "mediaType": "video", + "vast": "inline" + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/exemplary/with-user-sync.json b/adapters/contxtful/contxtfultest/exemplary/with-user-sync.json new file mode 100644 index 0000000000..461620f942 --- /dev/null +++ b/adapters/contxtful/contxtfultest/exemplary/with-user-sync.json @@ -0,0 +1,167 @@ +{ + "mockBidRequest": { + "id": "test-request-sync", + "imp": [ + { + "id": "test-imp-sync", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "sync-placement-1" + } + } + } + ], + "site": { + "id": "sync-demo-site", + "domain": "sync.example.com", + "page": "https://sync.example.com/sync-test", + "publisher": { + "id": "sync-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36", + "ip": "192.0.2.4", + "language": "en", + "dnt": 0 + }, + "user": { + "buyeruid": "contxtful-v1-demo-user-id-12345" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/DEMO123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-sync", + "bidder": "contxtful", + "params": { + "placementId": "sync-placement-1" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "DEMO123", + "version": "v1" + } + }, + "ortb2": { + "device": { + "dnt": 0, + "ip": "192.0.2.4", + "language": "en", + "ua": "Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36" + }, + "id": "test-request-sync", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "DEMO123", + "placementId": "sync-placement-1" + } + }, + "id": "test-imp-sync" + } + ], + "site": { + "domain": "sync.example.com", + "id": "sync-demo-site", + "page": "https://sync.example.com/sync-test", + "publisher": { + "id": "sync-publisher" + } + }, + "user": { + "buyeruid": "contxtful-v1-demo-user-id-12345" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-sync"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 3.75, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-imp-sync", + "adm": "<div style=\"width:300px;height:250px;background:#ffe0b2;text-align:center;line-height:250px;\">Contxtful Synced User Ad</div>", + "ttl": 300, + "creativeId": "sync-creative-456", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-sync&a=DEMO123&bidder=contxtful&impId=test-imp-sync&price=3.75&traceId=&random=0.000000&domain=sync.example.com&adRequestId=test-request-sync&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-sync&a=DEMO123&bidder=contxtful&impId=test-imp-sync&price=3.75&traceId=&random=0.000000&domain=sync.example.com&adRequestId=test-request-sync&w=300&h=250&f=b", + "ext": { + "contxtful": { + "userSync": "enabled", + "cookieStatus": "synced" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-sync", + "impid": "test-imp-sync", + "price": 3.75, + "adm": "<div style=\"width:300px;height:250px;background:#ffe0b2;text-align:center;line-height:250px;\">Contxtful Synced User Ad</div>", + "w": 300, + "h": 250, + "crid": "sync-creative-456", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-sync&a=DEMO123&bidder=contxtful&impId=test-imp-sync&price=3.75&traceId=&random=0.000000&domain=sync.example.com&adRequestId=test-request-sync&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-sync&a=DEMO123&bidder=contxtful&impId=test-imp-sync&price=3.75&traceId=&random=0.000000&domain=sync.example.com&adRequestId=test-request-sync&w=300&h=250&f=b", + "ext": { + "contxtful": { + "userSync": "enabled", + "cookieStatus": "synced" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/buyeruids-map-extraction.json b/adapters/contxtful/contxtfultest/supplemental/buyeruids-map-extraction.json new file mode 100644 index 0000000000..63b14fd8ba --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/buyeruids-map-extraction.json @@ -0,0 +1,158 @@ +{ + "mockBidRequest": { + "id": "test-request-buyeruids-map", + "imp": [ + { + "id": "test-imp-buyeruids-map", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "BUYERUID123", + "placementId": "buyeruids-placement-test" + } + } + } + ], + "site": { + "id": "buyeruids-site", + "domain": "buyeruids.example.com", + "page": "https://buyeruids.example.com/test" + }, + "user": { + "id": "test-user-buyeruids", + "ext": { + "prebid": { + "buyeruids": { + "contxtful": "foo" + } + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/BUYERUID123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-buyeruids-map", + "bidder": "contxtful", + "params": { + "placementId": "buyeruids-placement-test" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "BUYERUID123", + "version": "v1" + } + }, + "ortb2": { + "id": "test-request-buyeruids-map", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "BUYERUID123", + "placementId": "buyeruids-placement-test" + } + }, + "id": "test-imp-buyeruids-map" + } + ], + "site": { + "domain": "buyeruids.example.com", + "id": "buyeruids-site", + "page": "https://buyeruids.example.com/test" + }, + "user": { + "buyeruid": "foo", + "ext": { + "prebid": { + "buyeruids": { + "contxtful": "foo" + } + } + }, + "id": "test-user-buyeruids" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-buyeruids-map"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "requestId": "test-imp-buyeruids-map", + "cpm": 2.75, + "currency": "USD", + "width": 300, + "height": 250, + "creativeId": "buyeruids-creative-123", + "adm": "<div>BuyerUIDs Map Test Ad</div>", + "ttl": 300, + "netRevenue": true, + "mediaType": "banner", + "bidderCode": "contxtful", + "traceId": "buyeruids-trace-456", + "random": 0.654321, + "nurl": "https://monitoring.receptivity.io/v1/pbs/BUYERUID123/pbs-impression?b=contxtful-test-imp-buyeruids-map&a=BUYERUID123&bidder=contxtful&impId=test-imp-buyeruids-map&price=2.75&traceId=buyeruids-trace-456&random=0.654321&domain=buyeruids.example.com&adRequestId=test-request-buyeruids-map&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/BUYERUID123/pbs-billing?b=contxtful-test-imp-buyeruids-map&a=BUYERUID123&bidder=contxtful&impId=test-imp-buyeruids-map&price=2.75&traceId=buyeruids-trace-456&random=0.654321&domain=buyeruids.example.com&adRequestId=test-request-buyeruids-map&w=300&h=250&f=b" + } + ] + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-buyeruids-map", + "impid": "test-imp-buyeruids-map", + "price": 2.75, + "adm": "<div>BuyerUIDs Map Test Ad</div>", + "w": 300, + "h": 250, + "crid": "buyeruids-creative-123", + "nurl": "https://monitoring.receptivity.io/v1/pbs/BUYERUID123/pbs-impression?b=contxtful-test-imp-buyeruids-map&a=BUYERUID123&bidder=contxtful&impId=test-imp-buyeruids-map&price=2.75&traceId=buyeruids-trace-456&random=0.654321&domain=buyeruids.example.com&adRequestId=test-request-buyeruids-map&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/BUYERUID123/pbs-billing?b=contxtful-test-imp-buyeruids-map&a=BUYERUID123&bidder=contxtful&impId=test-imp-buyeruids-map&price=2.75&traceId=buyeruids-trace-456&random=0.654321&domain=buyeruids.example.com&adRequestId=test-request-buyeruids-map&w=300&h=250&f=b" + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [ + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/empty-response.json b/adapters/contxtful/contxtfultest/supplemental/empty-response.json new file mode 100644 index 0000000000..ec58f0460b --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/empty-response.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-empty", + "imp": [ + { + "id": "test-imp-empty", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "EMPTY123", + "placementId": "empty-placement" + } + } + } + ], + "site": { + "id": "empty-site", + "domain": "empty.example.com", + "page": "https://empty.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/EMPTY123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-empty", + "bidder": "contxtful", + "params": { + "placementId": "empty-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "EMPTY123", + "version": "v1" + } + }, + + "ortb2": { + "id": "test-request-empty", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "EMPTY123", + "placementId": "empty-placement" + } + }, + "id": "test-imp-empty" + } + ], + "site": { + "domain": "empty.example.com", + "id": "empty-site", + "page": "https://empty.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-empty"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "failed to parse response as Contxtful relay or Prebid.js format", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/http-204-no-content.json b/adapters/contxtful/contxtfultest/supplemental/http-204-no-content.json new file mode 100644 index 0000000000..ddadcc925d --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/http-204-no-content.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "test-request-empty", + "imp": [ + { + "id": "test-imp-empty", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "EMPTY123", + "placementId": "empty-placement" + } + } + } + ], + "site": { + "id": "empty-site", + "domain": "empty.example.com", + "page": "https://empty.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/EMPTY123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-empty", + "bidder": "contxtful", + "params": { + "placementId": "empty-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "EMPTY123", + "version": "v1" + } + }, + + "ortb2": { + "id": "test-request-empty", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "EMPTY123", + "placementId": "empty-placement" + } + }, + "id": "test-imp-empty" + } + ], + "site": { + "domain": "empty.example.com", + "id": "empty-site", + "page": "https://empty.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-empty"] + }, + "mockResponse": { + "status": 204, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/invalid-bidder-params.json b/adapters/contxtful/contxtfultest/supplemental/invalid-bidder-params.json new file mode 100644 index 0000000000..07e1cbc60a --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/invalid-bidder-params.json @@ -0,0 +1,32 @@ +{ + "mockBidRequest": { + "id": "test-request-invalid-bidder", + "imp": [ + { + "id": "test-imp-invalid-bidder", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": "invalid-bidder-json-string" + } + } + ], + "site": { + "id": "test-site", + "domain": "example.com", + "page": "https://example.com/test" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/invalid-imp-ext.json b/adapters/contxtful/contxtfultest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..f6bbd322dd --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/invalid-imp-ext.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-invalid-ext", + "imp": [ + { + "id": "test-imp-invalid-ext", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": "invalid-json-string" + } + ], + "site": { + "id": "test-site", + "domain": "example.com", + "page": "https://example.com/test" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/invalid-response.json b/adapters/contxtful/contxtfultest/supplemental/invalid-response.json new file mode 100644 index 0000000000..b4fc7bdc59 --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/invalid-response.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-invalid", + "imp": [ + { + "id": "test-imp-invalid", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "INVALID123", + "placementId": "invalid-placement" + } + } + } + ], + "site": { + "id": "invalid-site", + "domain": "invalid.example.com", + "page": "https://invalid.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/INVALID123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-invalid", + "bidder": "contxtful", + "params": { + "placementId": "invalid-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "INVALID123", + "version": "v1" + } + }, + + "ortb2": { + "id": "test-request-invalid", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "customerId": "INVALID123", + "placementId": "invalid-placement" + } + }, + "id": "test-imp-invalid" + } + ], + "site": { + "domain": "invalid.example.com", + "id": "invalid-site", + "page": "https://invalid.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-invalid"] + }, + "mockResponse": { + "status": 500, + "body": "Internal Server Error" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/no-adm.json b/adapters/contxtful/contxtfultest/supplemental/no-adm.json new file mode 100644 index 0000000000..1e8303acad --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/no-adm.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/NOMEDIA123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-no-mediatype", + "bidder": "contxtful", + "params": { + "placementId": "no-mediatype-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "NOMEDIA123", + "version": "v1" + } + }, + "ortb2": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-no-mediatype"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 1.75, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-imp-no-mediatype", + "mediaType": "banner", + "ttl": 300, + "creativeId": "no-mediatype-creative-456", + "netRevenue": true, + "nurl": "https://monitoring.receptivity.io/v1/pbs/NOMEDIA123/pbs-impression?b=contxtful-test-imp-no-mediatype&a=NOMEDIA123&bidder=contxtful&impId=test-imp-no-mediatype&price=1.75", + "burl": "https://monitoring.receptivity.io/v1/pbs/NOMEDIA123/pbs-billing?b=contxtful-test-imp-no-mediatype&a=NOMEDIA123&bidder=contxtful&impId=test-imp-no-mediatype&price=1.75" + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + ] + } + ], + "expectedMakeRequestsErrors": [ + ], + "expectedMakeBidsErrors": [ + { + "value": "bid has no ad markup", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/no-currency.json b/adapters/contxtful/contxtfultest/supplemental/no-currency.json new file mode 100644 index 0000000000..83b1e267aa --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/no-currency.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/NOMEDIA123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-no-mediatype", + "bidder": "contxtful", + "params": { + "placementId": "no-mediatype-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "NOMEDIA123", + "version": "v1" + } + }, + "ortb2": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-no-mediatype"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 2.50, + "width": 300, + "height": 250, + "requestId": "test-imp-banner", + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Contxtful Demo Ad</div>", + "ttl": 300, + "creativeId": "demo-creative-123", + "netRevenue": true, + "mediaType": "banner", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "contxtful-test-imp-banner", + "impid": "test-imp-banner", + "price": 2.50, + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Contxtful Demo Ad</div>", + "w": 300, + "h": 250, + "crid": "demo-creative-123", + "nurl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-impression?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "burl": "https://monitoring.receptivity.io/v1/pbs/DEMO123/pbs-billing?b=contxtful-test-imp-banner&a=DEMO123&bidder=contxtful&impId=test-imp-banner&price=2.50&traceId=&random=0.000000&domain=example.com&adRequestId=test-request-banner&w=300&h=250&f=b", + "ext": { + "contxtful": { + "reseller": "demo-reseller", + "version": "v1.0" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/no-mediatype.json b/adapters/contxtful/contxtfultest/supplemental/no-mediatype.json new file mode 100644 index 0000000000..166fd10831 --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/no-mediatype.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/NOMEDIA123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-no-mediatype", + "bidder": "contxtful", + "params": { + "placementId": "no-mediatype-placement" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "NOMEDIA123", + "version": "v1" + } + }, + "ortb2": { + "id": "test-request-no-mediatype", + "imp": [ + { + "id": "test-imp-no-mediatype", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "customerId": "NOMEDIA123", + "placementId": "no-mediatype-placement" + } + } + } + ], + "site": { + "id": "no-mediatype-site", + "domain": "nomediatype.example.com", + "page": "https://nomediatype.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-no-mediatype"] + }, + "mockResponse": { + "status": 200, + "body": [ + { + "cpm": 1.75, + "width": 300, + "height": 250, + "currency": "USD", + "requestId": "test-imp-no-mediatype", + "adm": "<div style=\"width:300px;height:250px;background:#ff0000;text-align:center;line-height:250px;\">No MediaType Ad</div>", + "ttl": 300, + "creativeId": "no-mediatype-creative-456", + "netRevenue": true, + "nurl": "https://monitoring.receptivity.io/v1/pbs/NOMEDIA123/pbs-impression?b=contxtful-test-imp-no-mediatype&a=NOMEDIA123&bidder=contxtful&impId=test-imp-no-mediatype&price=1.75", + "burl": "https://monitoring.receptivity.io/v1/pbs/NOMEDIA123/pbs-billing?b=contxtful-test-imp-no-mediatype&a=NOMEDIA123&bidder=contxtful&impId=test-imp-no-mediatype&price=1.75" + } + ] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + ] + } + ], + "expectedMakeRequestsErrors": [ + ], + "expectedMakeBidsErrors": [ + { + "value": "bid has no ad media type", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/contxtful/contxtfultest/supplemental/trace-format.json b/adapters/contxtful/contxtfultest/supplemental/trace-format.json new file mode 100644 index 0000000000..9cd68c14da --- /dev/null +++ b/adapters/contxtful/contxtfultest/supplemental/trace-format.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-trace", + "imp": [ + { + "id": "test-imp-trace", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "customerId": "TRACE123", + "placementId": "trace-placement-test" + } + } + } + ], + "site": { + "id": "trace-site", + "domain": "trace.example.com", + "page": "https://trace.example.com/test" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://prebid.receptivity.io/v1/pbs/TRACE123/bid", + "body": { + "bidRequests": [ + { + "bidId": "test-imp-trace", + "bidder": "contxtful", + "params": { + "placementId": "trace-placement-test" + } + } + ], + "bidderRequest": { + "bidderCode": "contxtful" + }, + "config": { + "contxtful": { + "customer": "TRACE123", + "version": "v1" + } + }, + "ortb2": { + "id": "test-request-trace", + "imp": [ + { + "banner": { + "format": [ + { + "h": 90, + "w": 728 + } + ] + }, + "ext": { + "bidder": { + "customerId": "TRACE123", + "placementId": "trace-placement-test" + } + }, + "id": "test-imp-trace" + } + ], + "site": { + "domain": "trace.example.com", + "id": "trace-site", + "page": "https://trace.example.com/test" + } + } + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "impIDs": ["test-imp-trace"] + }, + "mockResponse": { + "status": 200, + "body": [{"traceId": "simple-trace-test"}] + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + ] + } + ], + "expectedMakeBidsErrors": [ + ] +} \ No newline at end of file diff --git a/adapters/contxtful/params_test.go b/adapters/contxtful/params_test.go new file mode 100644 index 0000000000..bc7321f892 --- /dev/null +++ b/adapters/contxtful/params_test.go @@ -0,0 +1,47 @@ +package contxtful + +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 schema: %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderContxtful, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected valid 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 schema: %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderContxtful, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed invalid params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId": "12345", "customerId": "customer-123"}`, + `{"placementId": "placement-123", "customerId": "test-customer"}`, +} + +var invalidParams = []string{ + `{}`, + `{"placementId": "12345"}`, + `{"customerId": "customer-123"}`, + `{"placementId": 12345, "customerId": "customer-123"}`, + `{"placementId": "12345", "customerId": 123}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index af5c288967..e025eb0ed3 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -83,6 +83,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/connatix" "github.com/prebid/prebid-server/v3/adapters/connectad" "github.com/prebid/prebid-server/v3/adapters/consumable" + "github.com/prebid/prebid-server/v3/adapters/contxtful" "github.com/prebid/prebid-server/v3/adapters/conversant" "github.com/prebid/prebid-server/v3/adapters/copper6ssp" "github.com/prebid/prebid-server/v3/adapters/cpmstar" @@ -347,6 +348,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderConnatix: connatix.Builder, openrtb_ext.BidderConnectAd: connectad.Builder, openrtb_ext.BidderConsumable: consumable.Builder, + openrtb_ext.BidderContxtful: contxtful.Builder, openrtb_ext.BidderConversant: conversant.Builder, openrtb_ext.BidderCopper6ssp: copper6ssp.Builder, openrtb_ext.BidderCpmstar: cpmstar.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 435e92eb43..cdb6dcd2c7 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -99,6 +99,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderConnatix, BidderConnectAd, BidderConsumable, + BidderContxtful, BidderConversant, BidderCopper6ssp, BidderCpmstar, @@ -470,6 +471,7 @@ const ( BidderConnatix BidderName = "connatix" BidderConnectAd BidderName = "connectad" BidderConsumable BidderName = "consumable" + BidderContxtful BidderName = "contxtful" BidderConversant BidderName = "conversant" BidderCopper6ssp BidderName = "copper6ssp" BidderCpmstar BidderName = "cpmstar" diff --git a/openrtb_ext/imp_contxtful.go b/openrtb_ext/imp_contxtful.go new file mode 100644 index 0000000000..c86eba91c4 --- /dev/null +++ b/openrtb_ext/imp_contxtful.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtImpContxtful defines the contract for bidrequest.imp[i].ext.prebid.bidder.contxtful +type ExtImpContxtful struct { + PlacementId string `json:"placementId"` + CustomerId string `json:"customerId"` +} diff --git a/static/bidder-info/contxtful.yaml b/static/bidder-info/contxtful.yaml new file mode 100644 index 0000000000..8dbbe6272b --- /dev/null +++ b/static/bidder-info/contxtful.yaml @@ -0,0 +1,20 @@ +maintainer: + email: "contact@contxtful.com" +disabled: false +endpoint: "https://prebid.receptivity.io/v1/pbs/{{.AccountID}}/bid" + +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + iframe: + url: "https://sync.receptivity.io/pbs/iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "$UID" \ No newline at end of file diff --git a/static/bidder-params/contxtful.json b/static/bidder-params/contxtful.json new file mode 100644 index 0000000000..e1651898ab --- /dev/null +++ b/static/bidder-params/contxtful.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Contxtful Adapter Params", + "description": "A schema which validates params for the Contxtful adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "Placement ID", + "minLength": 1 + }, + "customerId": { + "type": "string", + "description": "Customer ID used to build the endpoint URL", + "minLength": 1 + } + }, + "required": ["placementId", "customerId"] +} \ No newline at end of file From f4640bbc1fee9262c894858eefc375958a3af7f9 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Wed, 24 Sep 2025 20:41:52 +0530 Subject: [PATCH 093/272] Modules: Exitpoint Hook typo fix (#4542) --- endpoints/openrtb2/test_utils.go | 8 +++---- hooks/hookexecution/executor.go | 6 +++--- hooks/hookexecution/mocks_test.go | 36 +++++++++++++++---------------- hooks/hookstage/exitpoint.go | 6 +++--- hooks/plan_test.go | 6 +++--- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go index bfab501682..e320a940e6 100644 --- a/endpoints/openrtb2/test_utils.go +++ b/endpoints/openrtb2/test_utils.go @@ -1753,14 +1753,14 @@ type mockUpdateResponseHook struct{} func (e mockUpdateResponseHook) HandleExitpointHook( _ context.Context, _ hookstage.ModuleInvocationContext, - _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} + _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPayload]{} c.AddMutation( - func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + func(payload hookstage.ExitpointPayload) (hookstage.ExitpointPayload, error) { payload.Response = &openrtb2.BidResponse{ID: "modified-id"} payload.W.Header().Set("Content-Type", "application/json") return payload, nil }, hookstage.MutationUpdate, "exitpoint", "bidResponse.json-response") - return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil + return hookstage.HookResult[hookstage.ExitpointPayload]{ChangeSet: c}, nil } diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go index d448bda806..0e5b28fff8 100644 --- a/hooks/hookexecution/executor.go +++ b/hooks/hookexecution/executor.go @@ -307,14 +307,14 @@ func (e *hookExecutor) ExecuteExitpointStage(response any, w http.ResponseWriter ctx context.Context, moduleCtx hookstage.ModuleInvocationContext, hook hookstage.Exitpoint, - payload hookstage.ExitpointPaylaod, - ) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { + payload hookstage.ExitpointPayload, + ) (hookstage.HookResult[hookstage.ExitpointPayload], error) { return hook.HandleExitpointHook(ctx, moduleCtx, payload) } stageName := hooks.StageExitpoint.String() executionCtx := e.newContext(stageName) - payload := hookstage.ExitpointPaylaod{W: w, Response: response} + payload := hookstage.ExitpointPayload{W: w, Response: response} outcome, payload, context, _ := executeStage(executionCtx, plan, payload, handler, e.metricEngine) outcome.Entity = entityExitpoint diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go index 202bd7a63f..3d9d982861 100644 --- a/hooks/hookexecution/mocks_test.go +++ b/hooks/hookexecution/mocks_test.go @@ -101,8 +101,8 @@ func (e mockRejectHook) HandleAuctionResponseHook(_ context.Context, _ hookstage return hookstage.HookResult[hookstage.AuctionResponsePayload]{Reject: true}, nil } -func (e mockRejectHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - return hookstage.HookResult[hookstage.ExitpointPaylaod]{Reject: true}, nil +func (e mockRejectHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + return hookstage.HookResult[hookstage.ExitpointPayload]{Reject: true}, nil } type mockTimeoutHook struct{} @@ -185,15 +185,15 @@ func (e mockTimeoutHook) HandleAuctionResponseHook(_ context.Context, _ hookstag return hookstage.HookResult[hookstage.AuctionResponsePayload]{ChangeSet: c}, nil } -func (e mockTimeoutHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { +func (e mockTimeoutHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { time.Sleep(2 * time.Millisecond) - c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} - c.AddMutation(func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + c := hookstage.ChangeSet[hookstage.ExitpointPayload]{} + c.AddMutation(func(payload hookstage.ExitpointPayload) (hookstage.ExitpointPayload, error) { payload.Response = &openrtb2.BidResponse{ID: "another-id"} return payload, nil }, hookstage.MutationUpdate, "exitpoint", "bidResponse.id") - return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil + return hookstage.HookResult[hookstage.ExitpointPayload]{ChangeSet: c}, nil } type mockModuleContextHook struct { @@ -235,9 +235,9 @@ func (e mockModuleContextHook) HandleAuctionResponseHook(_ context.Context, miCt return hookstage.HookResult[hookstage.AuctionResponsePayload]{ModuleContext: miCtx.ModuleContext}, nil } -func (e mockModuleContextHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { +func (e mockModuleContextHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { miCtx.ModuleContext = map[string]interface{}{e.key: e.val} - return hookstage.HookResult[hookstage.ExitpointPaylaod]{ModuleContext: miCtx.ModuleContext}, nil + return hookstage.HookResult[hookstage.ExitpointPayload]{ModuleContext: miCtx.ModuleContext}, nil } type mockFailureHook struct{} @@ -280,8 +280,8 @@ func (h mockErrorHook) HandleAuctionResponseHook(_ context.Context, miCtx hookst return hookstage.HookResult[hookstage.AuctionResponsePayload]{}, errors.New("unexpected error") } -func (h mockErrorHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - return hookstage.HookResult[hookstage.ExitpointPaylaod]{}, errors.New("unexpected error") +func (h mockErrorHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + return hookstage.HookResult[hookstage.ExitpointPayload]{}, errors.New("unexpected error") } type mockFailedMutationHook struct{} @@ -413,28 +413,28 @@ func (e mockUpdateBidResponseHook) HandleAuctionResponseHook(_ context.Context, type mockUpdateResponseHook struct{} -func (e mockUpdateResponseHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} +func (e mockUpdateResponseHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPayload]{} c.AddMutation( - func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + func(payload hookstage.ExitpointPayload) (hookstage.ExitpointPayload, error) { payload.Response = `<VAST version="2.0"/>` payload.W.Header().Set("Content-Type", "application/xml") return payload, nil }, hookstage.MutationUpdate, "exitpoint", "bidResponse.custom-response") - return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil + return hookstage.HookResult[hookstage.ExitpointPayload]{ChangeSet: c}, nil } type mockUpdateResponseAgainHook struct{} -func (e mockUpdateResponseAgainHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPaylaod) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - c := hookstage.ChangeSet[hookstage.ExitpointPaylaod]{} +func (e mockUpdateResponseAgainHook) HandleExitpointHook(_ context.Context, _ hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + c := hookstage.ChangeSet[hookstage.ExitpointPayload]{} c.AddMutation( - func(payload hookstage.ExitpointPaylaod) (hookstage.ExitpointPaylaod, error) { + func(payload hookstage.ExitpointPayload) (hookstage.ExitpointPayload, error) { payload.Response = &openrtb2.BidResponse{ID: "modified-id"} payload.W.Header().Set("Content-Type", "application/json") return payload, nil }, hookstage.MutationUpdate, "exitpoint", "bidResponse.json-response") - return hookstage.HookResult[hookstage.ExitpointPaylaod]{ChangeSet: c}, nil + return hookstage.HookResult[hookstage.ExitpointPayload]{ChangeSet: c}, nil } diff --git a/hooks/hookstage/exitpoint.go b/hooks/hookstage/exitpoint.go index 5746f2eae0..2726d4598c 100644 --- a/hooks/hookstage/exitpoint.go +++ b/hooks/hookstage/exitpoint.go @@ -18,15 +18,15 @@ type Exitpoint interface { HandleExitpointHook( context.Context, ModuleInvocationContext, - ExitpointPaylaod, - ) (HookResult[ExitpointPaylaod], error) + ExitpointPayload, + ) (HookResult[ExitpointPayload], error) } // ExitpointPayload contains a response of any type and a ResponseWriter. // The response is typically of type *openrtb2.BidResponse and can be modified // based on the module’s implementation. // Modules can also add custom headers depending on their response type. -type ExitpointPaylaod struct { +type ExitpointPayload struct { Response any W http.ResponseWriter } diff --git a/hooks/plan_test.go b/hooks/plan_test.go index 5cb44938f7..3266d2177f 100644 --- a/hooks/plan_test.go +++ b/hooks/plan_test.go @@ -982,7 +982,7 @@ type fakeExitpointHook struct{} func (f fakeExitpointHook) HandleExitpointHook( _ context.Context, _ hookstage.ModuleInvocationContext, - _ hookstage.ExitpointPaylaod, -) (hookstage.HookResult[hookstage.ExitpointPaylaod], error) { - return hookstage.HookResult[hookstage.ExitpointPaylaod]{}, nil + _ hookstage.ExitpointPayload, +) (hookstage.HookResult[hookstage.ExitpointPayload], error) { + return hookstage.HookResult[hookstage.ExitpointPayload]{}, nil } From f7d689af525bbdbd2c784a648162cf8e542dc881 Mon Sep 17 00:00:00 2001 From: richardngo-consumable <rngo@consumable.com> Date: Wed, 24 Sep 2025 10:20:16 -0500 Subject: [PATCH 094/272] Consumable: Declare geoscope (#4496) --- static/bidder-info/consumable.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/bidder-info/consumable.yaml b/static/bidder-info/consumable.yaml index 12e88d4735..1f348fc443 100644 --- a/static/bidder-info/consumable.yaml +++ b/static/bidder-info/consumable.yaml @@ -1,4 +1,8 @@ endpoint: "https://e.serverbid.com" +geoscope: + - USA + - CAN + - MEX maintainer: email: "prebid@consumable.com" gvlVendorID: 591 From e080d9874b44f83c18567796b9eb70b728329c50 Mon Sep 17 00:00:00 2001 From: Karim Mourra <karim@jwplayer.com> Date: Wed, 24 Sep 2025 13:18:02 -0300 Subject: [PATCH 095/272] Connatix: Copy entire imp[i].ext (#4521) --- adapters/connatix/connatix.go | 17 +- .../bid-request-imp-ext-persistence.json | 194 ++++++++++++++++++ adapters/connatix/models.go | 4 - 3 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 adapters/connatix/connatixtest/supplemental/bid-request-imp-ext-persistence.json diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 11cf7a146a..c479a2892f 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -222,15 +222,20 @@ func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer st imp.BidFloor = convertedValue } - impExt := impExt{ - Connatix: impExtConnatix{ - PlacementId: ext.Bidder.PlacementId, - ViewabilityPercentage: ext.Bidder.ViewabilityPercentage, - }, + var incomingExt map[string]interface{} + if err := jsonutil.Unmarshal(imp.Ext, &incomingExt); err != nil { + incomingExt = make(map[string]interface{}) + } + + delete(incomingExt, "bidder") + + incomingExt["connatix"] = impExtConnatix{ + PlacementId: ext.Bidder.PlacementId, + ViewabilityPercentage: ext.Bidder.ViewabilityPercentage, } var err error - imp.Ext, err = json.Marshal(impExt) + imp.Ext, err = json.Marshal(incomingExt) return err } diff --git a/adapters/connatix/connatixtest/supplemental/bid-request-imp-ext-persistence.json b/adapters/connatix/connatixtest/supplemental/bid-request-imp-ext-persistence.json new file mode 100644 index 0000000000..00b99b8188 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/bid-request-imp-ext-persistence.json @@ -0,0 +1,194 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "1-some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789", + "ext": { + "prebid": { + "source": "test", + "version": "1.0.0" + } + } + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id", + "viewabilityPercentage": 0.6 + }, + "random": { + "data_a": { + "data_1": "data_1" + }, + "data_b": { + "data_2": "data_2" + } + }, + "gpid": "test-gpid" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com?dc=us-east-2", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "displaymanagerver": "test-1.0.0", + "ext": { + "connatix": { + "placementId": "some-placement-id", + "viewabilityPercentage": 0.6 + }, + "random": { + "data_a": { + "data_1": "data_1" + }, + "data_b": { + "data_2": "data_2" + } + }, + "gpid": "test-gpid" + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + }, + "ext": { + "prebid": { + "source": "test", + "version": "1.0.0" + } + } + }, + "user": { + "buyeruid": "1-some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "adomain": [ + "test.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "test.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } diff --git a/adapters/connatix/models.go b/adapters/connatix/models.go index 95317d7e23..aebd51d097 100644 --- a/adapters/connatix/models.go +++ b/adapters/connatix/models.go @@ -12,10 +12,6 @@ type impExtIncoming struct { Bidder openrtb_ext.ExtImpConnatix `json:"bidder"` } -type impExt struct { - Connatix impExtConnatix `json:"connatix"` -} - type impExtConnatix struct { PlacementId string `json:"placementId,omitempty"` ViewabilityPercentage float64 `json:"viewabilityPercentage,omitempty"` From 5a668fad4f6f042a54b96255d258d46143c589f8 Mon Sep 17 00:00:00 2001 From: linux019 <anode.dev@gmail.com> Date: Wed, 24 Sep 2025 19:38:56 +0300 Subject: [PATCH 096/272] Fix: Preload Prometheus adapter connection dial metric labels when enabled (#4543) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- metrics/prometheus/preload.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/metrics/prometheus/preload.go b/metrics/prometheus/preload.go index 40e8c5b233..7311514760 100644 --- a/metrics/prometheus/preload.go +++ b/metrics/prometheus/preload.go @@ -185,13 +185,15 @@ func preloadLabelValues(m *Metrics, syncerKeys []string, moduleStageNames map[st adapterLabel: adapterValues, }) - preloadLabelValuesForCounter(m.adapterConnectionDialErrors, map[string][]string{ - adapterLabel: adapterValues, - }) - - preloadLabelValuesForHistogram(m.adapterConnectionDialTime, map[string][]string{ - adapterLabel: adapterValues, - }) + if !m.metricsDisabled.AdapterConnectionDialMetrics { + preloadLabelValuesForCounter(m.adapterConnectionDialErrors, map[string][]string{ + adapterLabel: adapterValues, + }) + + preloadLabelValuesForHistogram(m.adapterConnectionDialTime, map[string][]string{ + adapterLabel: adapterValues, + }) + } } preloadLabelValuesForHistogram(m.adapterRequestsTimer, map[string][]string{ From 13aacd078a8ee82e9e78974e1e38b80e33092dd1 Mon Sep 17 00:00:00 2001 From: Scott Kay <noreply@syntaxnode.com> Date: Wed, 24 Sep 2025 13:06:05 -0400 Subject: [PATCH 097/272] Host Option To Use OS Certs (#4536) --- config/config.go | 4 ++++ config/config_test.go | 2 ++ pbs/usersync.go | 5 +++-- router/router.go | 7 ++++++- server/ssl/ssl.go | 25 +++++++++++++++++++------ server/ssl/ssl_test.go | 4 +++- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/config/config.go b/config/config.go index a013bdc5a4..65f871ed97 100644 --- a/config/config.go +++ b/config/config.go @@ -79,6 +79,8 @@ type Configuration struct { AccountDefaults Account `mapstructure:"account_defaults"` // accountDefaultsJSON is the internal serialized form of AccountDefaults used for json merge accountDefaultsJSON json.RawMessage + // CertsUseSystem will use the host OS certificates instead of embedded certs. + CertsUseSystem bool `mapstructure:"certificates_use_system"` // Local private file containing SSL certificates PemCertsFile string `mapstructure:"certificates_file"` // Custom headers to handle request timeouts from queueing infrastructure @@ -1250,7 +1252,9 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("compression.response.enable_gzip", false) v.SetDefault("compression.request.enable_gzip", false) + v.SetDefault("certificates_use_system", false) v.SetDefault("certificates_file", "") + v.SetDefault("auto_gen_source_tid", true) v.SetDefault("generate_bid_id", false) v.SetDefault("generate_request_id", false) diff --git a/config/config_test.go b/config/config_test.go index 64c741eebe..3d7a0408b3 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -600,6 +600,7 @@ analytics: - code: agma-code publisher_id: publisher-id site_app_id: site-or-app-id +certificates_use_system: true `) func cmpStrings(t *testing.T, key, expected, actual string) { @@ -948,6 +949,7 @@ func TestFullConfig(t *testing.T) { cmpStrings(t, "analytics.agma.accounts.0.publisher_id", "publisher-id", cfg.Analytics.Agma.Accounts[0].PublisherId) cmpStrings(t, "analytics.agma.accounts.0.code", "agma-code", cfg.Analytics.Agma.Accounts[0].Code) cmpStrings(t, "analytics.agma.accounts.0.site_app_id", "site-or-app-id", cfg.Analytics.Agma.Accounts[0].SiteAppId) + cmpBools(t, "certificates_use_system", true, cfg.CertsUseSystem) } func TestValidateConfig(t *testing.T) { diff --git a/pbs/usersync.go b/pbs/usersync.go index bde61a7cbd..bd99eb7d10 100644 --- a/pbs/usersync.go +++ b/pbs/usersync.go @@ -2,6 +2,7 @@ package pbs import ( "crypto/tls" + "crypto/x509" "encoding/json" "fmt" "io" @@ -12,7 +13,6 @@ import ( "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/server/ssl" "github.com/prebid/prebid-server/v3/usersync" ) @@ -24,6 +24,7 @@ type UserSyncDeps struct { RecaptchaSecret string HostCookieConfig *config.HostCookie PriorityGroups [][]string + CertPool *x509.CertPool } // Struct for parsing json in google's response @@ -35,7 +36,7 @@ type googleResponse struct { func (deps *UserSyncDeps) VerifyRecaptcha(response string) error { ts := &http.Transport{ Proxy: http.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{RootCAs: ssl.GetRootCAPool()}, + TLSClientConfig: &tls.Config{RootCAs: deps.CertPool}, } client := &http.Client{ diff --git a/router/router.go b/router/router.go index 3bd3ad4b79..3f5970b965 100644 --- a/router/router.go +++ b/router/router.go @@ -130,7 +130,11 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R // For bid processing, we need both the hardcoded certificates and the certificates found in container's // local file system - certPool := ssl.GetRootCAPool() + certPool, certPoolCreateErr := ssl.CreateCertPool(cfg.CertsUseSystem) + if certPoolCreateErr != nil { + glog.Infof("Could not load root certificates: %s \n", certPoolCreateErr.Error()) + } + var readCertErr error certPool, readCertErr = ssl.AppendPEMFileToRootCAPool(certPool, cfg.PemCertsFile) if readCertErr != nil { @@ -301,6 +305,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R ExternalUrl: cfg.ExternalURL, RecaptchaSecret: cfg.RecaptchaSecret, PriorityGroups: cfg.UserSync.PriorityGroups, + CertPool: certPool, } r.GET("/setuid", endpoints.NewSetUIDEndpoint(cfg, syncersByBidder, gdprPermsBuilder, tcf2CfgBuilder, analyticsRunner, accounts, r.MetricsEngine)) diff --git a/server/ssl/ssl.go b/server/ssl/ssl.go index 8b00b7d191..ee754ed66d 100644 --- a/server/ssl/ssl.go +++ b/server/ssl/ssl.go @@ -2,20 +2,33 @@ package ssl import ( "crypto/x509" + "errors" "fmt" "os" ) // from https://medium.com/@kelseyhightower/optimizing-docker-images-for-static-binaries-b5696e26eb07 -var pool *x509.CertPool +var ( + ErrLoadEmbeddedCerts = errors.New("failed to load embedded certs") +) -func GetRootCAPool() *x509.CertPool { - if pool == nil { - pool = x509.NewCertPool() - pool.AppendCertsFromPEM(pemCerts) +func CreateCertPool(useSystem bool) (*x509.CertPool, error) { + if useSystem { + return x509.SystemCertPool() } - return pool + + return createCertPoolFromEmbedded() +} + +func createCertPoolFromEmbedded() (*x509.CertPool, error) { + pool := x509.NewCertPool() + + if ok := pool.AppendCertsFromPEM(pemCerts); !ok { + return pool, ErrLoadEmbeddedCerts + } + + return pool, nil } // Appends certificates to the `x509.CertPool` from a `.pem` private local file. On many Linux diff --git a/server/ssl/ssl_test.go b/server/ssl/ssl_test.go index e6abdbdcfa..b425ec9a63 100644 --- a/server/ssl/ssl_test.go +++ b/server/ssl/ssl_test.go @@ -5,11 +5,13 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCertsFromFilePoolExists(t *testing.T) { // Load hardcoded certificates found in ssl.go - certPool := GetRootCAPool() + certPool, certErr := createCertPoolFromEmbedded() + require.NoError(t, certErr) // Assert loaded certificates by looking at the length of the subjects array of strings subjects := certPool.Subjects() From fc184a88aaa498b3e42ecdd124632771fe824d10 Mon Sep 17 00:00:00 2001 From: Joshua Tomlinson <og.ginger@gmail.com> Date: Thu, 25 Sep 2025 07:03:41 -0700 Subject: [PATCH 098/272] CPMStar: imp.ext passthrough (#4450) --- adapters/cpmstar/cpmstar.go | 58 +++++++++++++-- ...nsion-field-preservation-multiple-imp.json | 72 +++++++++++++++++++ .../extension-field-preservation.json | 47 ++++++++++++ .../supplemental/missing-bidder-field.json | 28 ++++++++ .../supplemental/wrong-impression-ext.json | 26 ------- 5 files changed, 199 insertions(+), 32 deletions(-) create mode 100644 adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation-multiple-imp.json create mode 100644 adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation.json create mode 100644 adapters/cpmstar/cpmstartest/supplemental/missing-bidder-field.json delete mode 100644 adapters/cpmstar/cpmstartest/supplemental/wrong-impression-ext.json diff --git a/adapters/cpmstar/cpmstar.go b/adapters/cpmstar/cpmstar.go index f4f1390126..9aa3026c77 100644 --- a/adapters/cpmstar/cpmstar.go +++ b/adapters/cpmstar/cpmstar.go @@ -63,28 +63,74 @@ func preprocess(request *openrtb2.BidRequest) error { Message: "No Imps in Bid Request", } } - for i := 0; i < len(request.Imp); i++ { + + // Process each impression in the bid request + // + // FIELD HANDLING BEHAVIOR: + // - PRESERVES: All non-bidder fields (gpid, prebid, schain, custom fields, etc.) + // - TRANSFORMS: Extracts bidder config from nested structure and flattens to root level + // - EXPLICITLY REMOVES: Only the 'bidder' wrapper key (contents are preserved but flattened) + // + // Example transformation: + // Input: {"gpid": "/path", "bidder": {"placementId": 123}, "custom": "value"} + // Output: {"gpid": "/path", "placementId": 123, "custom": "value"} + for i := range request.Imp { var imp = &request.Imp[i] - var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + // Parse the original extension into a generic map to preserve all fields + var originalExt map[string]json.RawMessage + if err := jsonutil.Unmarshal(imp.Ext, &originalExt); err != nil { return &errortypes.BadInput{ Message: err.Error(), } } + // Extract the "bidder" field from the already parsed extension + bidderRaw, exists := originalExt["bidder"] + if !exists { + return &errortypes.BadInput{ + Message: "bidder field not found in impression extension", + } + } + if err := validateImp(imp); err != nil { return err } - var extImp openrtb_ext.ExtImpCpmstar - if err := jsonutil.Unmarshal(bidderExt.Bidder, &extImp); err != nil { + // Create new extension object that preserves all original fields except 'bidder' + newExt := make(map[string]json.RawMessage) + for key, value := range originalExt { + if key != "bidder" { + newExt[key] = value + } + } + + // Add bidder configuration fields directly to the root level + var bidderConfig map[string]interface{} + if err := jsonutil.Unmarshal(bidderRaw, &bidderConfig); err != nil { return &errortypes.BadInput{ Message: err.Error(), } } - imp.Ext = bidderExt.Bidder + for key, value := range bidderConfig { + valueBytes, err := json.Marshal(value) + if err != nil { + return &errortypes.BadInput{ + Message: err.Error(), + } + } + newExt[key] = valueBytes + } + + // Marshal the new extension object + modifiedExt, err := json.Marshal(newExt) + if err != nil { + return &errortypes.BadInput{ + Message: err.Error(), + } + } + imp.Ext = modifiedExt } return nil diff --git a/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation-multiple-imp.json b/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation-multiple-imp.json new file mode 100644 index 0000000000..a781dca8a2 --- /dev/null +++ b/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation-multiple-imp.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner1", + "bidder": { + "placementId": 154 + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner2", + "bidder": { + "placementId": 155 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "//host", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner1", + "placementId": 154 + } + }, + { + "id": "test-imp-id-2", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner2", + "placementId": 155 + } + } + ] + }, + "impIDs": ["test-imp-id", "test-imp-id-2"] + }, + "mockResponse": { + "status": 204 + } + } + ] + } + \ No newline at end of file diff --git a/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation.json b/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation.json new file mode 100644 index 0000000000..a777b00bd2 --- /dev/null +++ b/adapters/cpmstar/cpmstartest/supplemental/extension-field-preservation.json @@ -0,0 +1,47 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner1", + "bidder": { + "placementId": 154 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "//host", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner1", + "placementId": 154 + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ] +} diff --git a/adapters/cpmstar/cpmstartest/supplemental/missing-bidder-field.json b/adapters/cpmstar/cpmstartest/supplemental/missing-bidder-field.json new file mode 100644 index 0000000000..d392422803 --- /dev/null +++ b/adapters/cpmstar/cpmstartest/supplemental/missing-bidder-field.json @@ -0,0 +1,28 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "/homepage/banner1", + "someOtherField": "value" + } + } + ], + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/awesome/site" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "bidder field not found in impression extension", + "comparison": "literal" + } + ] +} diff --git a/adapters/cpmstar/cpmstartest/supplemental/wrong-impression-ext.json b/adapters/cpmstar/cpmstartest/supplemental/wrong-impression-ext.json deleted file mode 100644 index dc30faba5d..0000000000 --- a/adapters/cpmstar/cpmstartest/supplemental/wrong-impression-ext.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "mockBidRequest": { - "id": "rqid", - "imp": [ - { - "id": "impid", - "video": { - "w": 100, - "h": 200 - }, - "ext": { - "bidder": { - "placementId": "BOGUS" - } - } - } - ] - }, - - "expectedMakeRequestsErrors": [ - { - "value": "cannot unmarshal openrtb_ext.ExtImpCpmstar.PoolId: unexpected character", - "comparison": "startswith" - } - ] -} From 6ab64e4e368fd4085df13c05a5dd63b63cbbd733 Mon Sep 17 00:00:00 2001 From: metax-kehan <115962296+metax-kehan@users.noreply.github.com> Date: Thu, 9 Oct 2025 02:40:35 +0800 Subject: [PATCH 099/272] MetaX: Add redirect user sync (#4550) Signed-off-by: Kehan Pan <kehan.pan@metaxsoft.com> --- static/bidder-info/metax.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/bidder-info/metax.yaml b/static/bidder-info/metax.yaml index d9867322d0..9fc9488f78 100644 --- a/static/bidder-info/metax.yaml +++ b/static/bidder-info/metax.yaml @@ -16,3 +16,7 @@ capabilities: - video - native - audio +userSync: + redirect: + url: https://cm.metaxads.com/pixel?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}} + userMacro: "[UID]" \ No newline at end of file From 66e98bec168a847fe656dacbca0241a7bdefdb33 Mon Sep 17 00:00:00 2001 From: Denis Logachov <ckbo3hrk@gmail.com> Date: Wed, 8 Oct 2025 21:58:22 +0300 Subject: [PATCH 100/272] New Adapter: Xapads - AdKernel alias (#4534) --- static/bidder-info/xapads.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/xapads.yaml diff --git a/static/bidder-info/xapads.yaml b/static/bidder-info/xapads.yaml new file mode 100644 index 0000000000..87b551f17d --- /dev/null +++ b/static/bidder-info/xapads.yaml @@ -0,0 +1,9 @@ +aliasOf: adkernel +gvlVendorID: 1320 +userSync: + redirect: + url: "https://sync.adkernel.com/user-sync?t=image&zone=284803&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" + iframe: + url: "https://sync.adkernel.com/user-sync?t=iframe&zone=284803&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" From 76c02cf9796831f88f30db1b8c0aac296c5fecad Mon Sep 17 00:00:00 2001 From: Karim Mourra <karim@jwplayer.com> Date: Wed, 8 Oct 2025 16:10:00 -0300 Subject: [PATCH 101/272] Connatix: Add GPP macros (#4525) --- static/bidder-info/connatix.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/connatix.yaml b/static/bidder-info/connatix.yaml index b9b9430135..6759b7ef4d 100644 --- a/static/bidder-info/connatix.yaml +++ b/static/bidder-info/connatix.yaml @@ -13,8 +13,8 @@ capabilities: - video userSync: iframe: - url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&callback={{.RedirectURL}}" userMacro: "[UID]" redirect: - url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&callback={{.RedirectURL}}" userMacro: "[UID]" From d4524065a45309ebc7de951cb900a2793026a9ba Mon Sep 17 00:00:00 2001 From: Kacper Fus <kacper.fus@openx.com> Date: Wed, 8 Oct 2025 21:21:47 +0200 Subject: [PATCH 102/272] OpenX: Return buyer exts in response (#4507) Co-authored-by: Rafal Sieczka <rafal.sieczka@openx.com> --- adapters/openx/openx.go | 41 +++++++++++++ adapters/openx/openx_test.go | 114 +++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/adapters/openx/openx.go b/adapters/openx/openx.go index f10985f308..992baa0cdc 100644 --- a/adapters/openx/openx.go +++ b/adapters/openx/openx.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" @@ -32,6 +33,12 @@ type openxRespExt struct { FledgeAuctionConfigs map[string]json.RawMessage `json:"fledge_auction_configs,omitempty"` } +type oxBidExt struct { + DspId int `json:"dsp_id,string,omitempty"` + BrandId int `json:"brand_id,string,omitempty"` + BuyerId string `json:"buyer_id,omitempty"` +} + func (a *OpenxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errs []error var bannerAndNativeImps []openrtb2.Imp @@ -238,6 +245,7 @@ func (a *OpenxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRe Bid: &sb.Bid[i], BidType: getBidType(sb.Bid[i].MType, sb.Bid[i].ImpID, internalRequest.Imp), BidVideo: getBidVideo(&sb.Bid[i]), + BidMeta: getBidMeta(&sb.Bid[i]), }) } } @@ -298,3 +306,36 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co } return bidder, nil } + +func getBidMeta(bid *openrtb2.Bid) *openrtb_ext.ExtBidPrebidMeta { + if bid.Ext == nil { + return nil + } + + var ext *oxBidExt + if err := jsonutil.Unmarshal(bid.Ext, &ext); err != nil { + return nil + } + + buyerId := getBuyerIdFromExt(ext) + if buyerId <= 0 && ext.DspId <= 0 && ext.BrandId <= 0 { + return nil + } + + return &openrtb_ext.ExtBidPrebidMeta{ + NetworkID: ext.DspId, + AdvertiserID: buyerId, + BrandID: ext.BrandId, + } +} + +func getBuyerIdFromExt(ext *oxBidExt) int { + if ext.BuyerId == "" { + return 0 + } + buyerId, err := strconv.Atoi(ext.BuyerId) + if err != nil { + return 0 + } + return buyerId +} diff --git a/adapters/openx/openx_test.go b/adapters/openx/openx_test.go index 092e9190f9..fdfb37cc4a 100644 --- a/adapters/openx/openx_test.go +++ b/adapters/openx/openx_test.go @@ -2,6 +2,7 @@ package openx import ( "encoding/json" + "net/http" "testing" "github.com/prebid/openrtb/v20/openrtb2" @@ -33,6 +34,119 @@ func TestResponseWithCurrencies(t *testing.T) { assertCurrencyInBidResponse(t, "EUR", ¤cy) } +func TestOpenxAdapter_GetBidMeta(t *testing.T) { + testCases := []struct { + bid *openrtb2.Bid + expectedMeta *openrtb_ext.ExtBidPrebidMeta + }{ + { + &openrtb2.Bid{Ext: json.RawMessage(`malformed`)}, + nil, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{}`)}, + nil, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"dsp_id":"456","brand_id":"789","buyer_id":"123"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 123, NetworkID: 456, BrandID: 789}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"dsp_id":"456","brand_id":"malformed","buyer_id":"123"}`)}, + nil, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"dsp_id":"456","brand_id":"789","buyer_id":"123-456"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 0, NetworkID: 456, BrandID: 789}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"buyer_id":"123","dsp_id":"456"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 123, NetworkID: 456, BrandID: 0}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"buyer_id":"123","brand_id":"789"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 123, NetworkID: 0, BrandID: 789}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"dsp_id":"456","brand_id":"789"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 0, NetworkID: 456, BrandID: 789}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"buyer_id":"123"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 123, NetworkID: 0, BrandID: 0}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"dsp_id":"456"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 0, NetworkID: 456, BrandID: 0}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"brand_id":"789"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 0, NetworkID: 0, BrandID: 789}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"buyer_id":"123","dsp_id":"456"}`)}, + &openrtb_ext.ExtBidPrebidMeta{AdvertiserID: 123, NetworkID: 456, BrandID: 0}, + }, + { + &openrtb2.Bid{Ext: json.RawMessage(`{"buyer_id":"malformed","dsp_id":"malformed","brand_id":"malformed"}`)}, + nil, + }, + } + + for _, testCase := range testCases { + updatedMeta := getBidMeta(testCase.bid) + assert.Equal(t, testCase.expectedMeta, updatedMeta) + } +} + +func TestOpenxAdapter_MakeBids(t *testing.T) { + responseBody := `{"id":"test-request-id","seatbid":[{"seat":"openx","bid":[{"id":"all-buyer-ext","impid":"all-buyer-ext-imp-id","price":0.5,"adm":"some-test-ad","crid":"crid_10","ext":{"dsp_id":"123","brand_id":"456","buyer_id":"789"},"h":90,"w":728,"mtype":1},{"id":"only-dspId","impid":"only-dspId-imp-id","price":0.6,"adm":"some-test-ad","crid":"crid_11","ext":{"dsp_id":"321"},"h":90,"w":728,"mtype":1}]}],"cur":"USD"}` + response := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(responseBody), + } + adapter := &OpenxAdapter{bidderName: "", endpoint: ""} + bids, _ := adapter.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, response) + expectedBidderResponse := adapters.BidderResponse{ + Currency: "USD", + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "all-buyer-ext", + ImpID: "all-buyer-ext-imp-id", + Price: 0.5, + AdM: "some-test-ad", + CrID: "crid_10", + W: 728, + H: 90, + MType: 1, + Ext: json.RawMessage(`{"dsp_id":"123","brand_id":"456","buyer_id":"789"}`), + }, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: 123, BrandID: 456, AdvertiserID: 789}, + BidType: "banner", + BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 0, PrimaryCategory: ""}, + }, + { + Bid: &openrtb2.Bid{ + ID: "only-dspId", + ImpID: "only-dspId-imp-id", + Price: 0.6, + AdM: "some-test-ad", + CrID: "crid_11", + W: 728, + H: 90, + MType: 1, + Ext: json.RawMessage(`{"dsp_id":"321"}`), + }, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: 321}, + BidType: "banner", + BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 0, PrimaryCategory: ""}, + }, + }, + } + assert.Equal(t, expectedBidderResponse, *bids) +} + func assertCurrencyInBidResponse(t *testing.T, expectedCurrency string, currency *string) { bidder, buildErr := Builder(openrtb_ext.BidderOpenx, config.Adapter{ Endpoint: "http://rtb.openx.net/prebid"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) From 303a8d3d9c7691c65c305e26e6bdec210f81f41e Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov <dimurer@yandex-team.ru> Date: Wed, 8 Oct 2025 22:37:08 +0300 Subject: [PATCH 103/272] Yandex: Set referer and target-ref to site.page (#4488) --- adapters/yandex/yandex.go | 4 ++++ adapters/yandex/yandextest/exemplary/multi-format.json | 2 +- adapters/yandex/yandextest/exemplary/native.json | 2 +- adapters/yandex/yandextest/exemplary/simple-banner.json | 8 ++++---- adapters/yandex/yandextest/exemplary/simple-video.json | 2 +- .../supplemental/multiple-imps-some-malformed.json | 2 +- .../yandex/yandextest/supplemental/multiple-imps.json | 4 ++-- .../supplemental/simple-banner-empty-response.json | 2 +- .../supplemental/simple-banner-empty-seatbid.json | 2 +- .../yandextest/supplemental/simple-banner-sizes.json | 2 +- .../yandextest/supplemental/simple-banner-status-400.json | 2 +- .../supplemental/simple-banner-unknown-imp.json | 2 +- .../supplemental/simple-banner-unparsable-body.json | 2 +- .../yandextest/supplemental/simple-video-options.json | 2 +- 14 files changed, 21 insertions(+), 17 deletions(-) diff --git a/adapters/yandex/yandex.go b/adapters/yandex/yandex.go index 51c7c7ec29..c6a99e5a2e 100644 --- a/adapters/yandex/yandex.go +++ b/adapters/yandex/yandex.go @@ -316,6 +316,10 @@ func getReferer(request *openrtb2.BidRequest) string { return "" } + if request.Site.Page != "" { + return request.Site.Page + } + return request.Site.Domain } diff --git a/adapters/yandex/yandextest/exemplary/multi-format.json b/adapters/yandex/yandextest/exemplary/multi-format.json index abec409aad..84cc8d6044 100644 --- a/adapters/yandex/yandextest/exemplary/multi-format.json +++ b/adapters/yandex/yandextest/exemplary/multi-format.json @@ -39,7 +39,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=http%3A%2F%2Fexample.com", "headers": { "Accept": ["application/json"], "Accept-Language": ["en"], diff --git a/adapters/yandex/yandextest/exemplary/native.json b/adapters/yandex/yandextest/exemplary/native.json index f438f6e0da..d544f799b1 100644 --- a/adapters/yandex/yandextest/exemplary/native.json +++ b/adapters/yandex/yandextest/exemplary/native.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/exemplary/simple-banner.json b/adapters/yandex/yandextest/exemplary/simple-banner.json index cfb2236b24..aacb3b6f96 100644 --- a/adapters/yandex/yandextest/exemplary/simple-banner.json +++ b/adapters/yandex/yandextest/exemplary/simple-banner.json @@ -17,7 +17,7 @@ ], "site": { "domain": "www.example.com", - "page": "http://www.example.com" + "page": "http://www.example.com/path?query=value" }, "cur": [ "USD" @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com%2Fpath%3Fquery%3Dvalue", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" @@ -50,7 +50,7 @@ "application/json;charset=utf-8" ], "Referer": [ - "http://www.example.com" + "http://www.example.com/path?query=value" ], "Accept": [ "application/json" @@ -79,7 +79,7 @@ ], "site": { "domain": "www.example.com", - "page": "http://www.example.com" + "page": "http://www.example.com/path?query=value" }, "cur": [ "USD" diff --git a/adapters/yandex/yandextest/exemplary/simple-video.json b/adapters/yandex/yandextest/exemplary/simple-video.json index 42871e4d66..bda397d599 100644 --- a/adapters/yandex/yandextest/exemplary/simple-video.json +++ b/adapters/yandex/yandextest/exemplary/simple-video.json @@ -31,7 +31,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=http%3A%2F%2Fexample.com", "headers": { "Accept": ["application/json"], "Accept-Language": ["en"], diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json index c1b5aba636..2d6bc2c13a 100644 --- a/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json +++ b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json @@ -41,7 +41,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps.json b/adapters/yandex/yandextest/supplemental/multiple-imps.json index 50b7d0fe0f..b664df7a94 100644 --- a/adapters/yandex/yandextest/supplemental/multiple-imps.json +++ b/adapters/yandex/yandextest/supplemental/multiple-imps.json @@ -44,7 +44,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" @@ -128,7 +128,7 @@ }, { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=2&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=2&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json index 60ed42bcec..eebec7c4b5 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json index 9d4c10c6a1..a6124d8510 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json @@ -34,7 +34,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json index 1c215df0b9..9407a9400a 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json @@ -102,7 +102,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=4&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=4&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json index 8698c87a6b..0eb4adcf95 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json index 08c56dbc63..bd093c46fc 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json index 9ef2e6b28a..af55ce82a6 100644 --- a/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json @@ -32,7 +32,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=http%3A%2F%2Fwww.example.com", "headers": { "User-Agent": [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" diff --git a/adapters/yandex/yandextest/supplemental/simple-video-options.json b/adapters/yandex/yandextest/supplemental/simple-video-options.json index e139b37bdd..35c43a5c6a 100644 --- a/adapters/yandex/yandextest/supplemental/simple-video-options.json +++ b/adapters/yandex/yandextest/supplemental/simple-video-options.json @@ -29,7 +29,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=example.com", + "uri": "https://bs-metadsp.yandex.ru/prebid/123?imp-id=456&ssp-id=10500&target-ref=http%3A%2F%2Fexample.com", "headers": { "Accept": ["application/json"], "Accept-Language": ["en"], From 2c6d6aae06d2f4745a5e171384f82bab7abbf655 Mon Sep 17 00:00:00 2001 From: "a.popov" <60257866+allar15@users.noreply.github.com> Date: Wed, 8 Oct 2025 22:47:28 +0300 Subject: [PATCH 104/272] Nextmillennium: New fields and adapter version update (#4486) --- adapters/nextmillennium/nextmillennium.go | 6 +- .../exemplary/banner-empty-group-id.json | 2 +- .../exemplary/banner-with-ad-slots.json | 117 ++++++++++++++++++ .../exemplary/banner-with-allowed-ads.json | 117 ++++++++++++++++++ .../exemplary/banner-with-group-id.json | 2 +- .../exemplary/banner-with-group-id_app.json | 2 +- .../exemplary/banner-with-only-width.json | 2 +- .../exemplary/banner-with-wh.json | 2 +- .../exemplary/banner-wo-domain.json | 2 +- .../exemplary/banner-wo-size.json | 2 +- .../nextmillenniumtest/exemplary/banner.json | 2 +- .../exemplary/empty-banner-obj.json | 2 +- .../nextmillenniumtest/exemplary/video.json | 2 +- .../supplemental/empty-seatbid.json | 2 +- .../supplemental/error-response.json | 2 +- .../supplemental/no-content.json | 2 +- openrtb_ext/imp_nextmillennium.go | 6 +- static/bidder-params/nextmillennium.json | 17 ++- 18 files changed, 272 insertions(+), 17 deletions(-) create mode 100644 adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-ad-slots.json create mode 100644 adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-allowed-ads.json diff --git a/adapters/nextmillennium/nextmillennium.go b/adapters/nextmillennium/nextmillennium.go index 1b3cdeefdd..1b2546b662 100644 --- a/adapters/nextmillennium/nextmillennium.go +++ b/adapters/nextmillennium/nextmillennium.go @@ -14,7 +14,7 @@ import ( "github.com/prebid/prebid-server/v3/version" ) -const NM_ADAPTER_VERSION = "v1.0.0" +const NM_ADAPTER_VERSION = "v1.0.1" type adapter struct { endpoint string @@ -37,6 +37,8 @@ type nmExtPrebid struct { } type nmExtNMM struct { NmmFlags []string `json:"nmmFlags,omitempty"` + AdSlots []string `json:"adSlots,omitempty"` + AllowedAds []string `json:"allowedAds,omitempty"` ServerVersion string `json:"server_version,omitempty"` AdapterVersion string `json:"nm_version,omitempty"` } @@ -156,6 +158,8 @@ func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext } ext.NextMillennium.AdapterVersion = NM_ADAPTER_VERSION ext.NextMillennium.ServerVersion = version.Ver + ext.NextMillennium.AllowedAds = params.AllowedAds + ext.NextMillennium.AdSlots = params.AdSlots jsonExt, err := json.Marshal(ext) if err != nil { return &bidRequest diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json index f44bf6b01f..81388aa4a5 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json @@ -34,7 +34,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-ad-slots.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-ad-slots.json new file mode 100644 index 0000000000..cb6078b8b6 --- /dev/null +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-ad-slots.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "testid", + "imp": [ + { + "id": "123654", + "banner": { + "w": 320, + "h": 250 + }, + "ext": { + "bidder": { + "group_id": "7819", + "adSlots":["slot1, slot2"] + } + } + } + ], + "app": { + "domain": "www.example.com" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.nextmillmedia.com/openrtb2/auction", + "body":{ + "id": "testid", + "app": { + "domain": "www.example.com" + }, + "ext": { + "nextMillennium": { + "adSlots":["slot1, slot2"], + "nm_version":"v1.0.1" + }, + "prebid": { + "storedrequest": { + "id": "g7819;320x250;www.example.com" + }, + "server": { + "datacenter": "2", + "externalurl": "http://hosturl.com", + "gvlid": 1 + } + } + }, + "imp": [ + { + "banner": { + "h": 250, + "w": 320 + }, + "ext": { + "nextMillennium": {}, + "prebid": { + "storedrequest": { + "id": "g7819;320x250;www.example.com" + } + } + }, + "id": "123654" + } + ] + }, + "impIDs":["123654"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2", + "seatbid": [ + { + "bid": [ + { + "impid": "123654", + "id": "7457329903666272789", + "price": 0.5, + "adm": "Hello! It\"s a test ad!", + "adid": "96846035", + "adomain": ["test.addomain.com"], + "w": 300, + "h": 250, + "mtype":1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7457329903666272789", + "impid": "123654", + "price": 0.5, + "adm": "Hello! It\"s a test ad!", + "adid": "96846035", + "adomain": ["test.addomain.com"], + "w": 300, + "h": 250, + "mtype":1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-allowed-ads.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-allowed-ads.json new file mode 100644 index 0000000000..bdc43441b1 --- /dev/null +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-allowed-ads.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "testid", + "imp": [ + { + "id": "123654", + "banner": { + "w": 320, + "h": 250 + }, + "ext": { + "bidder": { + "group_id": "7819", + "allowedAds":["allowed_ad_1, allowed_ad_2"] + } + } + } + ], + "app": { + "domain": "www.example.com" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.nextmillmedia.com/openrtb2/auction", + "body":{ + "id": "testid", + "app": { + "domain": "www.example.com" + }, + "ext": { + "nextMillennium": { + "allowedAds":["allowed_ad_1, allowed_ad_2"], + "nm_version":"v1.0.1" + }, + "prebid": { + "storedrequest": { + "id": "g7819;320x250;www.example.com" + }, + "server": { + "datacenter": "2", + "externalurl": "http://hosturl.com", + "gvlid": 1 + } + } + }, + "imp": [ + { + "banner": { + "h": 250, + "w": 320 + }, + "ext": { + "nextMillennium": {}, + "prebid": { + "storedrequest": { + "id": "g7819;320x250;www.example.com" + } + } + }, + "id": "123654" + } + ] + }, + "impIDs":["123654"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "f7b3d2da-e762-410c-b069-424f92c4c4b2", + "seatbid": [ + { + "bid": [ + { + "impid": "123654", + "id": "7457329903666272789", + "price": 0.5, + "adm": "Hello! It\"s a test ad!", + "adid": "96846035", + "adomain": ["test.addomain.com"], + "w": 300, + "h": 250, + "mtype":1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7457329903666272789", + "impid": "123654", + "price": 0.5, + "adm": "Hello! It\"s a test ad!", + "adid": "96846035", + "adomain": ["test.addomain.com"], + "w": 300, + "h": 250, + "mtype":1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json index 4962cb01b3..61741c9653 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json @@ -45,7 +45,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json index 97152efd35..6518c5a4fa 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json @@ -41,7 +41,7 @@ }, "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json index 42f148ce83..9c6c11ecb0 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json @@ -30,7 +30,7 @@ }, "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json index 81fef905bf..dc0aa61b30 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json @@ -31,7 +31,7 @@ }, "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json index ab4d968204..247ae9d7b4 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json @@ -35,7 +35,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json index da8bd4bcbe..5502a88630 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json @@ -33,7 +33,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json index f28d4ab15b..1d2f6cda04 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json @@ -35,7 +35,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json index f3eb360e2e..c758bd0a8d 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json @@ -22,7 +22,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json index e31aa1e0ac..654c0cf78d 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json @@ -31,7 +31,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json index 02331a1d93..b9e417b7e1 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json @@ -34,7 +34,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json index fdf6d11943..58b081393f 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json @@ -30,7 +30,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json index d2641f62ea..593b422e76 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json @@ -30,7 +30,7 @@ "id": "testid", "ext": { "nextMillennium": { - "nm_version": "v1.0.0" + "nm_version": "v1.0.1" }, "prebid": { "storedrequest": { diff --git a/openrtb_ext/imp_nextmillennium.go b/openrtb_ext/imp_nextmillennium.go index 32b9579cd0..360706940f 100644 --- a/openrtb_ext/imp_nextmillennium.go +++ b/openrtb_ext/imp_nextmillennium.go @@ -1,6 +1,8 @@ package openrtb_ext type ImpExtNextMillennium struct { - GroupID string `json:"group_id,omitempty"` - PlacementID string `json:"placement_id"` + GroupID string `json:"group_id,omitempty"` + PlacementID string `json:"placement_id"` + AdSlots []string `json:"adSlots,omitempty"` + AllowedAds []string `json:"allowedAds,omitempty"` } diff --git a/static/bidder-params/nextmillennium.json b/static/bidder-params/nextmillennium.json index 743d72f89e..0f811e46fa 100644 --- a/static/bidder-params/nextmillennium.json +++ b/static/bidder-params/nextmillennium.json @@ -13,7 +13,22 @@ "type": "string", "minLength": 1, "description": "An id used to identify NextMillennium placement group" - } + }, + "adSlots": { + "type": "array", + "minItems": 1, + "description": "IDs which identifies the ad slots", + "items": { + "type": "string" + } + }, + "allowedAds": { + "type": "array", + "description": "List of allowed ads", + "items": { + "type": "string" + } + } }, "anyOf": [ { From 630bf989bdbdd8179ebd8b3cc743f01e6b693203 Mon Sep 17 00:00:00 2001 From: hhhjort <31041505+hhhjort@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:58:29 -0400 Subject: [PATCH 105/272] Accounts: Add coop cookiesync priority groups (#4561) --- config/account.go | 7 +- endpoints/cookie_sync.go | 10 +- endpoints/cookie_sync_test.go | 485 +++++++++++++++++++++++++++++++++- 3 files changed, 484 insertions(+), 18 deletions(-) diff --git a/config/account.go b/config/account.go index fbd434fcfb..2d2bfb5cd8 100644 --- a/config/account.go +++ b/config/account.go @@ -58,9 +58,10 @@ type Account struct { // CookieSync represents the account-level defaults for the cookie sync endpoint. type CookieSync struct { - DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` - MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` - DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` + DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` + MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` + DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` + PriorityGroups [][]string `mapstructure:"priority_groups" json:"priority_groups"` } // AccountCCPA represents account-specific CCPA configuration diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index 51fe8d5751..6a836ed976 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -184,7 +184,7 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, ma Bidders: request.Bidders, Cooperative: usersync.Cooperative{ Enabled: (request.CooperativeSync != nil && *request.CooperativeSync) || (request.CooperativeSync == nil && c.config.UserSync.Cooperative.EnabledByDefault), - PriorityGroups: c.config.UserSync.PriorityGroups, + PriorityGroups: c.findPriorityGroups(account.CookieSync), }, Debug: request.Debug, Limit: limit, @@ -333,6 +333,14 @@ func (c *cookieSyncEndpoint) setCooperativeSync(request cookieSyncRequest, cooki return request } +func (c *cookieSyncEndpoint) findPriorityGroups(accountCookieSyncConfig config.CookieSync) [][]string { + // Account-level config takes precedence over global config, which will be deprecated in the future + if accountCookieSyncConfig.DefaultCoopSync != nil { + return accountCookieSyncConfig.PriorityGroups + } + return c.config.UserSync.PriorityGroups +} + func parseTypeFilter(request *cookieSyncRequestFilterSettings) (usersync.SyncTypeFilter, error) { syncTypeFilter := usersync.SyncTypeFilter{ IFrame: cookieSyncBidderFilterAllowAll, diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index e1a7a1d8e1..6fc56f797b 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -586,15 +586,16 @@ func TestCookieSyncParseRequest(t *testing.T) { emptyActivityPoliciesRequest := privacy.NewRequestFromPolicies(privacy.Policies{}) testCases := []struct { - description string - givenConfig config.UserSync - givenBody io.Reader - givenGDPRConfig config.GDPR - givenCCPAEnabled bool - givenAccountRequired bool - expectedError string - expectedPrivacy macros.UserSyncPrivacy - expectedRequest usersync.Request + description string + givenConfig config.UserSync + givenBody io.Reader + givenGDPRConfig config.GDPR + givenCCPAEnabled bool + givenAccountRequired bool + givenAccountCoopDisabled bool + expectedError string + expectedPrivacy macros.UserSyncPrivacy + expectedRequest usersync.Request }{ { @@ -1014,9 +1015,12 @@ func TestCookieSyncParseRequest(t *testing.T) { givenCCPAEnabled: true, givenConfig: config.UserSync{ PriorityGroups: [][]string{{"a", "b", "c"}}, - Cooperative: config.UserSyncCooperative{}, + Cooperative: config.UserSyncCooperative{ + EnabledByDefault: true, + }, }, - expectedPrivacy: macros.UserSyncPrivacy{}, + givenAccountCoopDisabled: true, + expectedPrivacy: macros.UserSyncPrivacy{}, expectedRequest: usersync.Request{ Bidders: []string{"a", "b"}, Cooperative: usersync.Cooperative{ @@ -1046,10 +1050,11 @@ func TestCookieSyncParseRequest(t *testing.T) { givenConfig: config.UserSync{ PriorityGroups: [][]string{{"a", "b", "c"}}, Cooperative: config.UserSyncCooperative{ - EnabledByDefault: false, + EnabledByDefault: true, }, }, - expectedPrivacy: macros.UserSyncPrivacy{}, + givenAccountCoopDisabled: true, + expectedPrivacy: macros.UserSyncPrivacy{}, expectedRequest: usersync.Request{ Bidders: []string{"a", "b"}, Cooperative: usersync.Cooperative{ @@ -1115,6 +1120,11 @@ func TestCookieSyncParseRequest(t *testing.T) { cfg: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), }.Builder + testAccountData := json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30, "default_coop_sync": true}}`) + if test.givenAccountCoopDisabled { + testAccountData = json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30}}`) + } + endpoint := cookieSyncEndpoint{ config: &config.Configuration{ UserSync: test.givenConfig, @@ -1127,7 +1137,7 @@ func TestCookieSyncParseRequest(t *testing.T) { ccpaEnforce: test.givenCCPAEnabled, }, accountsFetcher: FakeAccountsFetcher{AccountData: map[string]json.RawMessage{ - "TestAccount": json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30, "default_coop_sync": true}}`), + "TestAccount": testAccountData, "DisabledAccount": json.RawMessage(`{"disabled":true}`), "ValidAccountInvalidActivities": json.RawMessage(`{"privacy":{"allowactivities":{"syncUser":{"rules":[{"condition":{"componentName": ["bidderA.bidderB.bidderC"]}}]}}}}`), }}, @@ -2502,3 +2512,450 @@ func TestSetCookieDeprecationHeader(t *testing.T) { }) } } + +func TestCookieSyncFindPriorityGroups(t *testing.T) { + testCases := []struct { + description string + givenGlobalConfig config.UserSync + givenAccountCookieSync config.CookieSync + expectedPriorityGroups [][]string + }{ + { + description: "Account-level config takes precedence when DefaultCoopSync is set", + givenGlobalConfig: config.UserSync{ + PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: ptrutil.ToPtr(true), + PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, + }, + expectedPriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, + }, + { + description: "Account-level config with false DefaultCoopSync still uses account config", + givenGlobalConfig: config.UserSync{ + PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: ptrutil.ToPtr(false), + PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, + }, + expectedPriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, + }, + { + description: "Falls back to global config when account DefaultCoopSync is nil", + givenGlobalConfig: config.UserSync{ + PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: nil, + PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, + }, + expectedPriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + { + description: "Empty account priority groups with DefaultCoopSync set", + givenGlobalConfig: config.UserSync{ + PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: ptrutil.ToPtr(true), + PriorityGroups: [][]string{}, + }, + expectedPriorityGroups: [][]string{}, + }, + { + description: "Nil account priority groups with DefaultCoopSync set", + givenGlobalConfig: config.UserSync{ + PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: ptrutil.ToPtr(true), + PriorityGroups: nil, + }, + expectedPriorityGroups: nil, + }, + { + description: "Empty global config when no account config present", + givenGlobalConfig: config.UserSync{ + PriorityGroups: nil, + }, + givenAccountCookieSync: config.CookieSync{ + DefaultCoopSync: nil, + PriorityGroups: [][]string{{"account1", "account2"}}, + }, + expectedPriorityGroups: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + endpoint := &cookieSyncEndpoint{ + config: &config.Configuration{ + UserSync: tc.givenGlobalConfig, + }, + } + + result := endpoint.findPriorityGroups(tc.givenAccountCookieSync) + assert.Equal(t, tc.expectedPriorityGroups, result) + }) + } +} + +// createAccountJSON creates a JSON representation of account config for testing +func createAccountJSON(priorityGroups [][]string, defaultCoopSync *bool) json.RawMessage { + account := map[string]interface{}{ + "cookie_sync": map[string]interface{}{ + "priority_groups": priorityGroups, + }, + } + + if defaultCoopSync != nil { + account["cookie_sync"].(map[string]interface{})["default_coop_sync"] = *defaultCoopSync + } + + jsonData, _ := json.Marshal(account) + return json.RawMessage(jsonData) +} + +func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { + // Setup test syncers + syncerA := MockSyncer{} + syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerA.On("Key").Return("appnexus").Maybe() + syncerA.On("SupportsType", mock.Anything).Return(true).Maybe() + syncerB := MockSyncer{} + syncerB.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderB.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerB.On("Key").Return("rubicon").Maybe() + syncerB.On("SupportsType", mock.Anything).Return(true).Maybe() + syncerC := MockSyncer{} + syncerC.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderC.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerC.On("Key").Return("pubmatic").Maybe() + syncerC.On("SupportsType", mock.Anything).Return(true).Maybe() + // Need to choose real bidder names because the standard chooser is hardcoded to validate against them + syncersByBidder := map[string]usersync.Syncer{ + "appnexus": &syncerA, + "rubicon": &syncerB, + "pubmatic": &syncerC, + } + + bidders := map[string]openrtb_ext.BidderName{ + "appnexus": openrtb_ext.BidderName("appnexus"), + "rubicon": openrtb_ext.BidderName("rubicon"), + "pubmatic": openrtb_ext.BidderName("pubmatic"), + } + + bidderInfo := map[string]config.BidderInfo{ + "appnexus": {}, + "rubicon": {}, + "pubmatic": {}, + } + + testCases := []struct { + description string + givenRequestBody string + givenAccountPriorityGroups [][]string + givenAccountDefaultCoopSync *bool + givenGlobalPriorityGroups [][]string + givenCooperativeEnabledByDef bool + shouldContainBidders []string + }{ + { + description: "Account-level priority groups used with cooperative sync enabled", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"rubicon", "pubmatic"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"ignored"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus", "rubicon", "pubmatic"}, + }, + { + description: "Global priority groups used when account DefaultCoopSync is nil", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"sovrn"}, + }, + givenAccountDefaultCoopSync: nil, // This should make it use global config + givenGlobalPriorityGroups: [][]string{{"rubicon"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus", "rubicon"}, + }, + { + description: "Empty account priority groups with cooperative enabled", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{}, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"rubicon"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus"}, + }, + { + description: "Priority groups ignored when cooperative sync disabled", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": false, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"rubicon", "pubmatic"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"rubicon"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus"}, // Only requested bidders + }, + { + description: "Priority groups used when cooperative default from Account", + givenRequestBody: `{"bidders":["appnexus"], "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"rubicon", "pubmatic"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"rubicon"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus", "rubicon", "pubmatic"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + // Setup mock analytics + mockAnalytics := MockAnalyticsRunner{} + mockAnalytics.On("LogCookieSyncObject", mock.AnythingOfType("*analytics.CookieSyncObject")).Return() + + mockMetrics := metrics.MetricsEngineMock{} + mockMetrics.On("RecordCookieSync", mock.Anything, mock.Anything, mock.Anything).Return() + mockMetrics.On("RecordSyncerRequest", mock.Anything, mock.Anything, mock.Anything).Return() + + // Create endpoint with test configuration + endpoint := NewCookieSyncEndpoint( + syncersByBidder, + &config.Configuration{ + UserSync: config.UserSync{ + PriorityGroups: tc.givenGlobalPriorityGroups, + Cooperative: config.UserSyncCooperative{ + EnabledByDefault: tc.givenCooperativeEnabledByDef, + }, + }, + HostCookie: config.HostCookie{Family: "prebid"}, + GDPR: config.GDPR{Enabled: true, DefaultValue: "0"}, + CCPA: config.CCPA{Enforce: false}, + BidderInfos: bidderInfo, + }, + fakePermissionsBuilder{ + permissions: &fakePermissions{}, + }.Builder, + fakeTCF2ConfigBuilder{ + cfg: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), + }.Builder, + &mockMetrics, + &mockAnalytics, + &FakeAccountsFetcher{ + AccountData: map[string]json.RawMessage{ + "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync), + }, + }, + bidders, + ) + // Create test request + request := httptest.NewRequest("POST", "/cookie_sync", strings.NewReader(tc.givenRequestBody)) + response := httptest.NewRecorder() + + // Execute endpoint + endpoint.Handle(response, request, nil) + + // Assert response status + assert.Equal(t, 200, response.Code) + + // Parse response + var syncResponse cookieSyncResponse + err := json.Unmarshal(response.Body.Bytes(), &syncResponse) + assert.NoError(t, err) + + // Verify bidder status contains expected bidders + actualBidders := make([]string, len(syncResponse.BidderStatus)) + for i, bs := range syncResponse.BidderStatus { + actualBidders[i] = bs.BidderCode + } + + // Check that expected bidders are present (order may vary due to shuffling) + for _, expected := range tc.shouldContainBidders { + assert.Contains(t, actualBidders, expected, "Expected bidder %s to be present in response", expected) + } + }) + } +} + +func TestCookieSyncPriorityGroupsEdgeCases(t *testing.T) { + // Setup basic syncers + syncerA := MockSyncer{} + syncerA.On("Key").Return("bidderA") + syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerA.On("SupportsType", mock.Anything).Return(true).Maybe() + + syncersByBidder := map[string]usersync.Syncer{ + "sovrn": &syncerA, + } + + bidders := map[string]openrtb_ext.BidderName{ + "sovrn": openrtb_ext.BidderName("sovrn"), + } + + bidderInfo := map[string]config.BidderInfo{ + "sovrn": {}, + } + + testCases := []struct { + description string + givenRequestBody string + givenAccountPriorityGroups [][]string + givenAccountDefaultCoopSync *bool + givenGlobalPriorityGroups [][]string + expectedStatus int + expectError bool + }{ + { + description: "Nil priority groups in account config", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: nil, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"sovrn"}}, + expectedStatus: 200, + expectError: false, + }, + { + description: "Empty priority groups in account config", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{}, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"sovrn"}}, + expectedStatus: 200, + expectError: false, + }, + { + description: "Priority groups with empty nested arrays", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {}, // empty group + {"bidderB"}, // valid group + {}, // another empty group + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{}, + expectedStatus: 200, + expectError: false, + }, + { + description: "Priority groups with unknown bidders", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"unknownBidder1", "unknownBidder2"}, + {"anotherUnknownBidder"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{}, + expectedStatus: 200, + expectError: false, // Should not error, just ignore unknown bidders + }, + { + description: "Priority groups with limit constraint", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 1, "account": "test_account"}`, // limit to 1 + givenAccountPriorityGroups: [][]string{ + {"appnexus", "rubicon", "pubmatic"}, // many bidders in priority + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{}, + expectedStatus: 200, + expectError: false, // Should respect limit and not error + }, + { + description: "Very large priority groups", + givenRequestBody: `{"bidders":["sovrn"], "coopSync": true, "limit": 100, "account": "test_account"}`, + givenAccountPriorityGroups: func() [][]string { + // Create large priority groups + groups := make([][]string, 10) + for i := 0; i < 10; i++ { + group := make([]string, 50) + for j := 0; j < 50; j++ { + group[j] = fmt.Sprintf("bidder%d_%d", i, j) + } + groups[i] = group + } + return groups + }(), + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{}, + expectedStatus: 200, + expectError: false, // Should handle large groups gracefully + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + // Setup mock analytics + mockAnalytics := MockAnalyticsRunner{} + mockAnalytics.On("LogCookieSyncObject", mock.AnythingOfType("*analytics.CookieSyncObject")).Return() + + mockMetrics := metrics.MetricsEngineMock{} + mockMetrics.On("RecordCookieSync", mock.Anything, mock.Anything, mock.Anything).Return() + mockMetrics.On("RecordSyncerRequest", mock.Anything, mock.Anything, mock.Anything).Return() + + // Create endpoint with test configuration + endpoint := NewCookieSyncEndpoint( + syncersByBidder, + &config.Configuration{ + UserSync: config.UserSync{ + PriorityGroups: tc.givenGlobalPriorityGroups, + Cooperative: config.UserSyncCooperative{ + EnabledByDefault: false, + }, + }, + HostCookie: config.HostCookie{Family: "prebid"}, + GDPR: config.GDPR{Enabled: true, DefaultValue: "0"}, + CCPA: config.CCPA{Enforce: false}, + BidderInfos: bidderInfo, + }, + fakePermissionsBuilder{ + permissions: &fakePermissions{}, + }.Builder, + fakeTCF2ConfigBuilder{ + cfg: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), + }.Builder, + &mockMetrics, + &mockAnalytics, + &FakeAccountsFetcher{ + AccountData: map[string]json.RawMessage{ + "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync), + }, + }, + bidders, + ) + + // Create test request + request := httptest.NewRequest("POST", "/cookie_sync", strings.NewReader(tc.givenRequestBody)) + response := httptest.NewRecorder() + + // Execute endpoint + endpoint.Handle(response, request, nil) + + // Assert response status + assert.Equal(t, tc.expectedStatus, response.Code) + + if !tc.expectError && tc.expectedStatus == 200 { + // Parse response to ensure it's valid JSON and has expected structure + var syncResponse cookieSyncResponse + err := json.Unmarshal(response.Body.Bytes(), &syncResponse) + assert.NoError(t, err, "Response should be valid JSON") + + // Should always contain the requested bidder at minimum + actualBidders := make([]string, len(syncResponse.BidderStatus)) + for i, bs := range syncResponse.BidderStatus { + actualBidders[i] = bs.BidderCode + } + + assert.Contains(t, actualBidders, "sovrn", "Response should always contain requested bidder") + + // Verify response structure is valid + assert.NotEmpty(t, syncResponse.Status, "Response should have a status") + } + }) + } +} From ff5702b6bb1e630eb1b55e7878bf32f05fac598a Mon Sep 17 00:00:00 2001 From: Marc-Enzo Bonnafon <marcenzo.bonnafon@gmail.com> Date: Mon, 20 Oct 2025 18:00:23 +0100 Subject: [PATCH 106/272] Mobkoi: Remove url endpoint override (#4555) --- adapters/mobkoi/mobkoi.go | 13 +- adapters/mobkoi/mobkoi_test.go | 2 +- .../mobkoitest/exemplary/banner-web.json | 6 +- .../mobkoitest/exemplary/fallback-uri.json | 148 ------------------ .../mobkoitest/exemplary/use-tag-id.json | 8 +- .../mobkoitest/supplemental/bad-input.json | 6 +- .../mobkoitest/supplemental/bad-response.json | 6 +- .../mobkoitest/supplemental/no-content.json | 6 +- .../supplemental/no-tag-nor-placement-id.json | 4 +- .../mobkoitest/supplemental/server-error.json | 6 +- adapters/mobkoi/params_test.go | 9 +- openrtb_ext/imp_mobkoi.go | 3 +- static/bidder-params/mobkoi.json | 5 - 13 files changed, 17 insertions(+), 205 deletions(-) delete mode 100644 adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json diff --git a/adapters/mobkoi/mobkoi.go b/adapters/mobkoi/mobkoi.go index 19a6d34d52..3f8bffe0c5 100644 --- a/adapters/mobkoi/mobkoi.go +++ b/adapters/mobkoi/mobkoi.go @@ -3,8 +3,6 @@ package mobkoi import ( "errors" "net/http" - "net/url" - "strings" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" @@ -49,15 +47,6 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte } } - uri := a.endpoint - if ext.Bidder.AdServerBaseUrl != "" { - baseURL, err := url.ParseRequestURI(ext.Bidder.AdServerBaseUrl) - if err == nil { // Ensure parsing doesn't fail - baseURL.Path = strings.TrimRight(baseURL.Path, "/") + "/bid" - uri = baseURL.String() - } - } - if request.User != nil && request.User.Consent != "" { user := *request.User userExt, err := jsonutil.Marshal(UserExt{ @@ -81,7 +70,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte requestData := &adapters.RequestData{ Method: http.MethodPost, - Uri: uri, + Uri: a.endpoint, Body: requestJSON, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(request.Imp), diff --git a/adapters/mobkoi/mobkoi_test.go b/adapters/mobkoi/mobkoi_test.go index 36ee6a329c..19bcdb8385 100644 --- a/adapters/mobkoi/mobkoi_test.go +++ b/adapters/mobkoi/mobkoi_test.go @@ -10,7 +10,7 @@ import ( func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderMobkoi, config.Adapter{ - Endpoint: "http://any.url"}, + Endpoint: "http://dev.mobkoi.com/bid"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { diff --git a/adapters/mobkoi/mobkoitest/exemplary/banner-web.json b/adapters/mobkoi/mobkoitest/exemplary/banner-web.json index 45c33e215b..6c1824a26b 100644 --- a/adapters/mobkoi/mobkoitest/exemplary/banner-web.json +++ b/adapters/mobkoi/mobkoitest/exemplary/banner-web.json @@ -28,8 +28,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } @@ -65,8 +64,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } diff --git a/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json b/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json deleted file mode 100644 index 6f40bcd2e3..0000000000 --- a/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user", - "consent": "consent-string" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id1", - "tagid": "", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "invalid" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json" - ], - "Accept": [ - "application/json" - ] - }, - "uri": "http://any.url", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id1", - "tagid": "placementId", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "invalid" - } - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user", - "consent": "consent-string", - "ext": { - "consent": "consent-string" - } - }, - "tmax": 1000 - }, - "impIDs": [ - "some-impression-id1" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id1", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50, - "lurl": "mobkoi/loss", - "nurl": "mobkoi/win" - } - ], - "type": "banner", - "seat": "mobkoi" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id1", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "w": 320, - "h": 50, - "lurl": "mobkoi/loss", - "nurl": "mobkoi/win" - }, - "type": "banner", - "seat": "mobkoi" - } - ] - } - ] -} diff --git a/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json b/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json index cc26ab0cd1..149c9675c7 100644 --- a/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json +++ b/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json @@ -27,9 +27,7 @@ "h": 50 }, "ext": { - "bidder": { - "adServerBaseUrl": "http://dev.mobkoi.com" - } + "bidder": {} } } ] @@ -63,9 +61,7 @@ "h": 50 }, "ext": { - "bidder": { - "adServerBaseUrl": "http://dev.mobkoi.com" - } + "bidder": {} } } ], diff --git a/adapters/mobkoi/mobkoitest/supplemental/bad-input.json b/adapters/mobkoi/mobkoitest/supplemental/bad-input.json index cac08d4bbf..47f8b14dd8 100644 --- a/adapters/mobkoi/mobkoitest/supplemental/bad-input.json +++ b/adapters/mobkoi/mobkoitest/supplemental/bad-input.json @@ -28,8 +28,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } @@ -65,8 +64,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } diff --git a/adapters/mobkoi/mobkoitest/supplemental/bad-response.json b/adapters/mobkoi/mobkoitest/supplemental/bad-response.json index 4d872c212d..82361bd1b6 100644 --- a/adapters/mobkoi/mobkoitest/supplemental/bad-response.json +++ b/adapters/mobkoi/mobkoitest/supplemental/bad-response.json @@ -28,8 +28,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } @@ -65,8 +64,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } diff --git a/adapters/mobkoi/mobkoitest/supplemental/no-content.json b/adapters/mobkoi/mobkoitest/supplemental/no-content.json index e645bb079b..729d6b4edc 100644 --- a/adapters/mobkoi/mobkoitest/supplemental/no-content.json +++ b/adapters/mobkoi/mobkoitest/supplemental/no-content.json @@ -28,8 +28,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } @@ -65,8 +64,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } diff --git a/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json b/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json index a3c943f3a0..fde8909cd8 100644 --- a/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json +++ b/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json @@ -27,9 +27,7 @@ "h": 50 }, "ext": { - "bidder": { - "adServerBaseUrl": "http://dev.mobkoi.com" - } + "bidder": {} } } ] diff --git a/adapters/mobkoi/mobkoitest/supplemental/server-error.json b/adapters/mobkoi/mobkoitest/supplemental/server-error.json index c21b37863c..240daad6cd 100644 --- a/adapters/mobkoi/mobkoitest/supplemental/server-error.json +++ b/adapters/mobkoi/mobkoitest/supplemental/server-error.json @@ -28,8 +28,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } @@ -65,8 +64,7 @@ }, "ext": { "bidder": { - "placementId": "placementId", - "adServerBaseUrl": "http://dev.mobkoi.com" + "placementId": "placementId" } } } diff --git a/adapters/mobkoi/params_test.go b/adapters/mobkoi/params_test.go index 1ee1fd9779..ea279629dc 100644 --- a/adapters/mobkoi/params_test.go +++ b/adapters/mobkoi/params_test.go @@ -43,9 +43,6 @@ var validParams = []string{ `{}`, `{"foo":"bar"}`, `{"placementId":"abc"}`, - `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.com"}`, - `{"adServerBaseUrl":"http://dev.mobkoi.com"}`, - `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.com"}`, } var invalidParams = []string{ @@ -55,9 +52,5 @@ var invalidParams = []string{ `1`, `1.0`, `[]`, - `{"placementId":123, "adServerBaseUrl":"mobkoi.com"}`, - `{"placementId":"abc", "adServerBaseUrl":"https://ikea.ad.com"}`, - `{"placementId":"abc", "adServerBaseUrl":"http://ikea.ad.com"}`, - `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.net"}`, - `{"placementId":"abc", "adServerBaseUrl":"https://mobkoi.com"}`, + `{"placementId":123}`, } diff --git a/openrtb_ext/imp_mobkoi.go b/openrtb_ext/imp_mobkoi.go index ffb110e9ea..0410be2fd8 100644 --- a/openrtb_ext/imp_mobkoi.go +++ b/openrtb_ext/imp_mobkoi.go @@ -1,6 +1,5 @@ package openrtb_ext type ImpExtMobkoi struct { - PlacementID string `json:"placementId"` - AdServerBaseUrl string `json:"adServerBaseUrl"` + PlacementID string `json:"placementId"` } diff --git a/static/bidder-params/mobkoi.json b/static/bidder-params/mobkoi.json index 8286229b03..6858a48a67 100644 --- a/static/bidder-params/mobkoi.json +++ b/static/bidder-params/mobkoi.json @@ -7,11 +7,6 @@ "placementId": { "type": "string", "description": "Placement ID" - }, - "adServerBaseUrl": { - "type": "string", - "description": "Mobkoi's ad server url", - "pattern": "^https?://[^.]+\\.mobkoi\\.com$" } } } From b568b7222e84129e6ffcf347751f9e7db60b399c Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Mon, 20 Oct 2025 14:23:07 -0400 Subject: [PATCH 107/272] GDPR: Move enforcement processing upstream (#4567) --- endpoints/openrtb2/amp_auction.go | 10 +- endpoints/openrtb2/auction.go | 32 +- endpoints/openrtb2/auction_test.go | 217 +++++++++ endpoints/openrtb2/video_auction.go | 6 + exchange/exchange.go | 61 +-- exchange/exchange_test.go | 72 +-- .../exchangetest/gdpr-geo-eu-off-device.json | 2 +- exchange/exchangetest/gdpr-geo-eu-off.json | 2 +- .../gdpr-geo-eu-on-featureflag-off.json | 2 +- ...-geo-eu-on-with-account-eea-countries.json | 2 +- exchange/exchangetest/gdpr-geo-eu-on.json | 2 +- exchange/gdpr.go | 51 -- exchange/gdpr_test.go | 228 --------- exchange/targeting_test.go | 1 - exchange/utils.go | 15 +- exchange/utils_test.go | 37 +- gdpr/utils.go | 95 ++++ gdpr/utils_test.go | 440 ++++++++++++++++++ 18 files changed, 833 insertions(+), 442 deletions(-) delete mode 100644 exchange/gdpr.go delete mode 100644 exchange/gdpr_test.go create mode 100644 gdpr/utils.go create mode 100644 gdpr/utils_test.go diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 9d5bc24896..37419e4a59 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -27,7 +27,6 @@ import ( "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/gdpr" "github.com/prebid/prebid-server/v3/hooks" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" @@ -126,8 +125,6 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h StartTime: start, } - // Set this as an AMP request in Metrics. - labels := metrics.Labels{ Source: metrics.DemandWeb, RType: metrics.ReqTypeAMP, @@ -249,13 +246,14 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h return } - tcf2Config := gdpr.NewTCF2Config(deps.cfg.GDPR.TCF2, account.GDPR) - activityControl = privacy.NewActivityControl(&account.Privacy) hookExecutor.SetActivityControl(activityControl) hookExecutor.SetAccount(account) + tcf2Config, gdprSignal, gdprEnforced, gdprErrs := deps.processGDPR(reqWrapper, account.GDPR, labels.RType) + errL = append(errL, gdprErrs...) + secGPC := r.Header.Get("Sec-GPC") auctionRequest := &exchange.AuctionRequest{ @@ -275,6 +273,8 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h TCF2Config: tcf2Config, Activities: activityControl, TmaxAdjustments: deps.tmaxAdjustments, + GDPRSignal: gdprSignal, + GDPREnforced: gdprEnforced, } auctionResponse, err := deps.ex.HoldAuction(ctx, auctionRequest, nil) diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 692d92733f..f03e6bc489 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -202,8 +202,6 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http return } - tcf2Config := gdpr.NewTCF2Config(deps.cfg.GDPR.TCF2, account.GDPR) - activityControl = privacy.NewActivityControl(&account.Privacy) hookExecutor.SetActivityControl(activityControl) @@ -218,6 +216,9 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http defer cancel() } + tcf2Config, gdprSignal, gdprEnforced, gdprErrs := deps.processGDPR(req, account.GDPR, labels.RType) + errL = append(errL, gdprErrs...) + // Read Usersyncs/Cookie decoder := usersync.Base64Decoder{} usersyncs := usersync.ReadCookie(r, decoder, &deps.cfg.HostCookie) @@ -260,6 +261,8 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http TCF2Config: tcf2Config, Activities: activityControl, TmaxAdjustments: deps.tmaxAdjustments, + GDPRSignal: gdprSignal, + GDPREnforced: gdprEnforced, } auctionResponse, err := deps.ex.HoldAuction(ctx, auctionRequest, nil) defer func() { @@ -2059,3 +2062,28 @@ func checkIfAppRequest(request []byte) (bool, error) { } return false, nil } + +// processGDPR handles GDPR signal processing and policy building. +// It returns the created privacy policy (if GDPR is enforced) and any errors encountered. +func (deps *endpointDeps) processGDPR(req *openrtb_ext.RequestWrapper, accountGDPR config.AccountGDPR, requestType metrics.RequestType) ( + gdpr.TCF2ConfigReader, gdpr.Signal, bool, []error) { + + tcf2Config := gdpr.NewTCF2Config(deps.cfg.GDPR.TCF2, accountGDPR) + + var gdprErrs []error + + // Retrieve EEA countries configuration from either host or account settings + eeaCountries := gdpr.SelectEEACountries(deps.cfg.GDPR.EEACountries, accountGDPR.EEACountries) + + // Make our best guess if GDPR applies + gdprDefaultValue := gdpr.ParseGDPRDefaultValue(req, deps.cfg.GDPR.DefaultValue, eeaCountries) + gdprSignal, err := gdpr.GetGDPR(req) + if err != nil { + gdprErrs = append(gdprErrs, err) + } + + channelEnabled := tcf2Config.ChannelEnabled(exchange.ChannelTypeMap[requestType]) + gdprEnforced := gdpr.EnforceGDPR(gdprSignal, gdprDefaultValue, channelEnabled) + + return tcf2Config, gdprSignal, gdprEnforced, gdprErrs +} diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index 09f2d013c3..65e520a219 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -29,6 +29,7 @@ import ( "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/exchange" + "github.com/prebid/prebid-server/v3/gdpr" "github.com/prebid/prebid-server/v3/hooks" "github.com/prebid/prebid-server/v3/hooks/hookexecution" "github.com/prebid/prebid-server/v3/hooks/hookstage" @@ -6399,3 +6400,219 @@ func TestValidateUser(t *testing.T) { }) } } + +func TestProcessGDPR(t *testing.T) { + testCases := []struct { + name string + req *openrtb_ext.RequestWrapper + accountGDPR config.AccountGDPR + requestType metrics.RequestType + cfg *config.Configuration + expectedGDPREnforced bool + expectedGDPRSignal gdpr.Signal + expectedErrorCount int + }{ + { + name: "gdpr-not-enforced-no-signal", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{}, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeAMP, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: false, + expectedGDPRSignal: gdpr.SignalAmbiguous, + expectedErrorCount: 0, + }, + { + name: "gdpr-enforced-with-signal-yes", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Regs: &openrtb2.Regs{ + GDPR: ptrutil.ToPtr[int8](1), + }, + User: &openrtb2.User{ + Consent: "consent-string", + }, + }, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeORTB2Web, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: true, + expectedGDPRSignal: gdpr.SignalYes, + expectedErrorCount: 0, + }, + { + name: "gdpr-enforced-with-eea-country", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + Geo: &openrtb2.Geo{ + Country: "FRA", + }, + }, + }, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeORTB2Web, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: true, + expectedGDPRSignal: gdpr.SignalAmbiguous, + expectedErrorCount: 0, + }, + { + name: "gdpr-not-enforced-with-non-eea-country", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + Geo: &openrtb2.Geo{ + Country: "USA", + }, + }, + }, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeORTB2Web, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: false, + expectedGDPRSignal: gdpr.SignalAmbiguous, + expectedErrorCount: 0, + }, + { + name: "gdpr-with-gpp-string", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Regs: &openrtb2.Regs{ + GDPR: ptrutil.ToPtr[int8](1), + GPP: "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA", + }, + }, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeORTB2Web, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: true, + expectedGDPRSignal: gdpr.SignalYes, + expectedErrorCount: 0, + }, + { + name: "gdpr-with-account-eea-countries", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + Geo: &openrtb2.Geo{ + Country: "ITA", + }, + }, + }, + }, + accountGDPR: config.AccountGDPR{ + EEACountries: []string{"ITA", "ESP"}, + }, + requestType: metrics.ReqTypeORTB2Web, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "1", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: true, + }, + }, + }, + expectedGDPREnforced: true, + expectedGDPRSignal: gdpr.SignalAmbiguous, + expectedErrorCount: 0, + }, + { + name: "gdpr-disabled-tcf2", + req: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Regs: &openrtb2.Regs{ + GDPR: ptrutil.ToPtr[int8](1), + }, + }, + }, + accountGDPR: config.AccountGDPR{}, + requestType: metrics.ReqTypeAMP, + cfg: &config.Configuration{ + GDPR: config.GDPR{ + Enabled: true, + DefaultValue: "0", + EEACountries: []string{"FRA", "DEU"}, + TCF2: config.TCF2{ + Enabled: false, + }, + }, + }, + expectedGDPREnforced: false, + expectedGDPRSignal: gdpr.SignalYes, + expectedErrorCount: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + deps := &endpointDeps{ + cfg: tc.cfg, + } + + tcf2Config, gdprSignal, gdprEnforced, gdprErrs := deps.processGDPR( + tc.req, + tc.accountGDPR, + tc.requestType, + ) + + assert.Equal(t, tc.expectedGDPREnforced, gdprEnforced) + assert.Equal(t, tc.expectedGDPRSignal, gdprSignal) + assert.Len(t, gdprErrs, tc.expectedErrorCount) + assert.NotNil(t, tcf2Config) + }) + } +} diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index 65b5fd520a..e82981c3d4 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -304,6 +304,9 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re return } + tcf2Config, gdprSignal, gdprEnforced, gdprErrs := deps.processGDPR(bidReqWrapper, account.GDPR, labels.RType) + errL = append(errL, gdprErrs...) + // Populate any "missing" OpenRTB fields with info from other sources, (e.g. HTTP request headers). if errs := deps.setFieldsImplicitly(r, bidReqWrapper, account); len(errs) > 0 { errL = append(errL, errs...) @@ -332,8 +335,11 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re GlobalPrivacyControlHeader: secGPC, PubID: labels.PubID, HookExecutor: hookexecution.EmptyHookExecutor{}, + TCF2Config: tcf2Config, TmaxAdjustments: deps.tmaxAdjustments, Activities: activityControl, + GDPRSignal: gdprSignal, + GDPREnforced: gdprEnforced, } auctionResponse, err := deps.ex.HoldAuction(ctx, auctionRequest, &debugLog) diff --git a/exchange/exchange.go b/exchange/exchange.go index 8c5d698275..1915e7b273 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -72,7 +72,6 @@ type exchange struct { gdprPermsBuilder gdpr.PermissionsBuilder currencyConverter *currency.RateConverter externalURL string - gdprDefaultValue gdpr.Signal privacyConfig config.Privacy categoriesFetcher stored_requests.CategoryFetcher bidIDGenerator BidIDGenerator @@ -142,11 +141,6 @@ func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid bidderToSyncerKey[bidder] = syncer.Key() } - gdprDefaultValue := gdpr.SignalYes - if cfg.GDPR.DefaultValue == "0" { - gdprDefaultValue = gdpr.SignalNo - } - privacyConfig := config.Privacy{ CCPA: cfg.CCPA, GDPR: cfg.GDPR, @@ -173,7 +167,6 @@ func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid externalURL: cfg.ExternalURL, gdprPermsBuilder: gdprPermsBuilder, me: metricsEngine, - gdprDefaultValue: gdprDefaultValue, privacyConfig: privacyConfig, bidIDGenerator: &bidIDGenerator{cfg.GenerateBidID}, hostSChainNode: cfg.HostSChainNode, @@ -223,6 +216,8 @@ type AuctionRequest struct { QueryParams url.Values BidderResponseStartTime time.Time TmaxAdjustments *TmaxAdjustmentsPreprocessed + GDPRSignal gdpr.Signal + GDPREnforced bool } // BidderRequest holds the bidder specific request and all other @@ -321,20 +316,9 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog recordImpMetrics(r.BidRequestWrapper, e.me) - // Retrieve EEA countries configuration from either host or account settings - eeaCountries := selectEEACountries(e.privacyConfig.GDPR.EEACountries, r.Account.GDPR.EEACountries) - - // Make our best guess if GDPR applies - gdprDefaultValue := e.parseGDPRDefaultValue(r.BidRequestWrapper, eeaCountries) - gdprSignal, err := getGDPR(r.BidRequestWrapper) - if err != nil { - return nil, err - } - channelEnabled := r.TCF2Config.ChannelEnabled(channelTypeMap[r.LegacyLabels.RType]) - gdprEnforced := enforceGDPR(gdprSignal, gdprDefaultValue, channelEnabled) dsaWriter := dsa.Writer{ Config: r.Account.Privacy.DSA, - GDPRInScope: gdprEnforced, + GDPRInScope: r.GDPREnforced, } if err := dsaWriter.Write(r.BidRequestWrapper); err != nil { return nil, err @@ -350,7 +334,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog Prebid: *requestExtPrebid, SChain: requestExt.GetSChain(), } - bidderRequests, privacyLabels, errs := e.requestSplitter.cleanOpenRTBRequests(ctx, *r, requestExtLegacy, gdprSignal, gdprEnforced, bidAdjustmentFactors) + bidderRequests, privacyLabels, errs := e.requestSplitter.cleanOpenRTBRequests(ctx, *r, requestExtLegacy, bidAdjustmentFactors) for _, err := range errs { if errortypes.ReadCode(err) == errortypes.InvalidImpFirstPartyDataErrorCode { return nil, err @@ -625,29 +609,6 @@ func buildMultiBidMap(prebid *openrtb_ext.ExtRequestPrebid) map[string]openrtb_e return multiBidMap } -func (e *exchange) parseGDPRDefaultValue(r *openrtb_ext.RequestWrapper, eeaCountries []string) gdpr.Signal { - gdprDefaultValue := e.gdprDefaultValue - - var geo *openrtb2.Geo - if r.User != nil && r.User.Geo != nil { - geo = r.User.Geo - } else if r.Device != nil && r.Device.Geo != nil { - geo = r.Device.Geo - } - - if geo != nil { - // If the country is in the EEA list, GDPR applies. - // Otherwise, if the country code is properly formatted (3 characters), GDPR does not apply. - if isEEACountry(geo.Country, eeaCountries) { - gdprDefaultValue = gdpr.SignalYes - } else if len(geo.Country) == 3 { - gdprDefaultValue = gdpr.SignalNo - } - } - - return gdprDefaultValue -} - func recordImpMetrics(r *openrtb_ext.RequestWrapper, metricsEngine metrics.MetricsEngine) { for _, impInRequest := range r.GetImp() { var impLabels metrics.ImpLabels = metrics.ImpLabels{ @@ -1682,17 +1643,3 @@ func setSeatNonBid(bidResponseExt *openrtb_ext.ExtBidResponse, seatNonBidBuilder bidResponseExt.Prebid.SeatNonBid = seatNonBidBuilder.Slice() return bidResponseExt } - -func isEEACountry(country string, eeaCountries []string) bool { - if len(eeaCountries) == 0 { - return false - } - - country = strings.ToUpper(country) - for _, c := range eeaCountries { - if strings.ToUpper(c) == country { - return true - } - } - return false -} diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index d86f1b33bc..cb214e8994 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -2124,10 +2124,13 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { } var gdprDefaultValue string + var gdprSignal gdpr.Signal if spec.AssumeGDPRApplies { gdprDefaultValue = "1" + gdprSignal = gdpr.SignalYes } else { gdprDefaultValue = "0" + gdprSignal = gdpr.SignalNo } privacyConfig := config.Privacy{ @@ -2138,13 +2141,9 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { Enforce: spec.EnforceLMT, }, GDPR: config.GDPR{ - Enabled: spec.GDPREnabled, DefaultValue: gdprDefaultValue, EEACountries: eeac, EEACountriesMap: eeacMap, - TCF2: config.TCF2{ - Enabled: spec.GDPREnabled, - }, }, } bidIdGenerator := &fakeBidIDGenerator{} @@ -2204,6 +2203,8 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { HookExecutor: &hookexecution.EmptyHookExecutor{}, TCF2Config: gdpr.NewTCF2Config(privacyConfig.GDPR.TCF2, config.AccountGDPR{}), Activities: activityControl, + GDPRSignal: gdprSignal, + GDPREnforced: spec.GDPREnforced, } if spec.MultiBid != nil { @@ -2435,11 +2436,6 @@ func newExchangeForTests(t *testing.T, filename string, aliases map[string]strin bidderToSyncerKey[string(bidderName)] = string(bidderName) } - gdprDefaultValue := gdpr.SignalYes - if privacyConfig.GDPR.DefaultValue == "0" { - gdprDefaultValue = gdpr.SignalNo - } - var hostSChainNode *openrtb2.SupplyChainNode if exSpec.HostSChainFlag { hostSChainNode = &openrtb2.SupplyChainNode{ @@ -2470,7 +2466,6 @@ func newExchangeForTests(t *testing.T, filename string, aliases map[string]strin cache: &wellBehavedCache{}, cacheTime: 0, currencyConverter: currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)), - gdprDefaultValue: gdprDefaultValue, gdprPermsBuilder: gdprPermsBuilder, privacyConfig: privacyConfig, categoriesFetcher: categoriesFetcher, @@ -5501,7 +5496,7 @@ func (ms *MockSigner) Sign(destinationURL string, body []byte) (string, error) { } type exchangeSpec struct { - GDPREnabled bool `json:"gdpr_enabled"` + GDPREnforced bool `json:"gdpr_enforced"` FloorsEnabled bool `json:"floors_enabled"` IncomingRequest exchangeRequest `json:"incomingRequest"` OutgoingRequests map[string]*bidderSpec `json:"outgoingRequests"` @@ -6531,61 +6526,6 @@ func TestGetBidderPreferredMediaType(t *testing.T) { } } -func TestIsEEACountry(t *testing.T) { - eeaCountries := []string{"FRA", "DEU", "ITA", "ESP", "NLD"} - - tests := []struct { - name string - country string - eeaList []string - expected bool - }{ - { - name: "Country_in_EEA", - country: "FRA", - eeaList: eeaCountries, - expected: true, - }, - { - name: "Country_in_EEA_lowercase", - country: "fra", - eeaList: eeaCountries, - expected: true, - }, - { - name: "Country_not_in_EEA", - country: "USA", - eeaList: eeaCountries, - expected: false, - }, - { - name: "Empty_country_string", - country: "", - eeaList: eeaCountries, - expected: false, - }, - { - name: "EEA_list_is_empty", - country: "FRA", - eeaList: []string{}, - expected: false, - }, - { - name: "EEA_list_is_nil", - country: "FRA", - eeaList: nil, - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := isEEACountry(tt.country, tt.eeaList) - assert.Equal(t, tt.expected, result) - }) - } -} - type mockRequestValidator struct { errors []error } diff --git a/exchange/exchangetest/gdpr-geo-eu-off-device.json b/exchange/exchangetest/gdpr-geo-eu-off-device.json index 7a3dd95b3a..a48d31b9b6 100644 --- a/exchange/exchangetest/gdpr-geo-eu-off-device.json +++ b/exchange/exchangetest/gdpr-geo-eu-off-device.json @@ -1,6 +1,6 @@ { "assume_gdpr_applies": false, - "gdpr_enabled": true, + "gdpr_enforced": true, "incomingRequest": { "ortbRequest": { "id": "some-request-id", diff --git a/exchange/exchangetest/gdpr-geo-eu-off.json b/exchange/exchangetest/gdpr-geo-eu-off.json index 1fbfae489d..57e18e9762 100644 --- a/exchange/exchangetest/gdpr-geo-eu-off.json +++ b/exchange/exchangetest/gdpr-geo-eu-off.json @@ -1,6 +1,6 @@ { "assume_gdpr_applies": false, - "gdpr_enabled": true, + "gdpr_enforced": true, "incomingRequest": { "ortbRequest": { "id": "some-request-id", diff --git a/exchange/exchangetest/gdpr-geo-eu-on-featureflag-off.json b/exchange/exchangetest/gdpr-geo-eu-on-featureflag-off.json index 6e75e73f64..95b5a980a7 100644 --- a/exchange/exchangetest/gdpr-geo-eu-on-featureflag-off.json +++ b/exchange/exchangetest/gdpr-geo-eu-on-featureflag-off.json @@ -1,6 +1,6 @@ { "assume_gdpr_applies": true, - "gdpr_enabled": false, + "gdpr_enforced": false, "incomingRequest": { "ortbRequest": { "id": "some-request-id", diff --git a/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json b/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json index a9b469fb11..fdf4983172 100644 --- a/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json +++ b/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json @@ -1,7 +1,7 @@ { "assume_gdpr_applies": true, "account_eea_countries": ["POL"], - "gdpr_enabled": true, + "gdpr_enforced": true, "incomingRequest": { "ortbRequest": { "id": "some-request-id", diff --git a/exchange/exchangetest/gdpr-geo-eu-on.json b/exchange/exchangetest/gdpr-geo-eu-on.json index 63d712db31..2240fdba8e 100644 --- a/exchange/exchangetest/gdpr-geo-eu-on.json +++ b/exchange/exchangetest/gdpr-geo-eu-on.json @@ -1,6 +1,6 @@ { "assume_gdpr_applies": true, - "gdpr_enabled": true, + "gdpr_enforced": true, "incomingRequest": { "ortbRequest": { "id": "some-request-id", diff --git a/exchange/gdpr.go b/exchange/gdpr.go deleted file mode 100644 index 8c58a77b46..0000000000 --- a/exchange/gdpr.go +++ /dev/null @@ -1,51 +0,0 @@ -package exchange - -import ( - gpplib "github.com/prebid/go-gpp" - gppConstants "github.com/prebid/go-gpp/constants" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/openrtb_ext" - gppPolicy "github.com/prebid/prebid-server/v3/privacy/gpp" -) - -// getGDPR will pull the gdpr flag from an openrtb request -func getGDPR(req *openrtb_ext.RequestWrapper) (gdpr.Signal, error) { - if req.Regs != nil && len(req.Regs.GPPSID) > 0 { - if gppPolicy.IsSIDInList(req.Regs.GPPSID, gppConstants.SectionTCFEU2) { - return gdpr.SignalYes, nil - } - return gdpr.SignalNo, nil - } - if req.Regs != nil && req.Regs.GDPR != nil { - return gdpr.IntSignalParse(int(*req.Regs.GDPR)) - } - return gdpr.SignalAmbiguous, nil - -} - -// getConsent will pull the consent string from an openrtb request -func getConsent(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) (consent string, err error) { - if i := gppPolicy.IndexOfSID(gpp, gppConstants.SectionTCFEU2); i >= 0 { - consent = gpp.Sections[i].GetValue() - return - } - if req.User != nil { - return req.User.Consent, nil - } - return -} - -// enforceGDPR determines if GDPR should be enforced based on the request signal and whether the channel is enabled -func enforceGDPR(signal gdpr.Signal, defaultValue gdpr.Signal, channelEnabled bool) bool { - gdprApplies := signal == gdpr.SignalYes || (signal == gdpr.SignalAmbiguous && defaultValue == gdpr.SignalYes) - return gdprApplies && channelEnabled -} - -// SelectEEACountries selects the EEA countries based on host and account configurations. -// Account-level configuration takes precedence over the host-level configuration. -func selectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { - if accountEEACountries != nil { - return accountEEACountries - } - return hostEEACountries -} diff --git a/exchange/gdpr_test.go b/exchange/gdpr_test.go deleted file mode 100644 index 1ef69d498b..0000000000 --- a/exchange/gdpr_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package exchange - -import ( - "testing" - - gpplib "github.com/prebid/go-gpp" - gppConstants "github.com/prebid/go-gpp/constants" - "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/stretchr/testify/assert" -) - -func TestGetGDPR(t *testing.T) { - tests := []struct { - description string - giveRegs *openrtb2.Regs - wantGDPR gdpr.Signal - wantError bool - }{ - { - description: "Regs Ext GDPR = 0", - giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](0)}, - wantGDPR: gdpr.SignalNo, - }, - { - description: "Regs Ext GDPR = 1", - giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](1)}, - wantGDPR: gdpr.SignalYes, - }, - { - description: "Regs Ext GDPR = null", - giveRegs: &openrtb2.Regs{GDPR: nil}, - wantGDPR: gdpr.SignalAmbiguous, - }, - { - description: "Regs is nil", - giveRegs: nil, - wantGDPR: gdpr.SignalAmbiguous, - }, - { - description: "Regs Ext GDPR = null, GPPSID has tcf2", - giveRegs: &openrtb2.Regs{GDPR: nil, GPPSID: []int8{2}}, - wantGDPR: gdpr.SignalYes, - }, - { - description: "Regs Ext GDPR = 1, GPPSID has uspv1", - giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](1), GPPSID: []int8{6}}, - wantGDPR: gdpr.SignalNo, - }, - { - description: "Regs Ext GDPR = 0, GPPSID has tcf2", - giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](0), GPPSID: []int8{2}}, - wantGDPR: gdpr.SignalYes, - }, - { - description: "Regs Ext is nil, GPPSID has tcf2", - giveRegs: &openrtb2.Regs{GPPSID: []int8{2}}, - wantGDPR: gdpr.SignalYes, - }, - { - description: "Regs Ext is nil, GPPSID has uspv1", - giveRegs: &openrtb2.Regs{GPPSID: []int8{6}}, - wantGDPR: gdpr.SignalNo, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - req := openrtb_ext.RequestWrapper{ - BidRequest: &openrtb2.BidRequest{ - Regs: tt.giveRegs, - }, - } - result, err := getGDPR(&req) - assert.Equal(t, tt.wantGDPR, result) - - if tt.wantError { - assert.NotNil(t, err) - } else { - assert.Nil(t, err) - } - }) - } -} - -func TestGetConsent(t *testing.T) { - tests := []struct { - description string - giveUser *openrtb2.User - giveGPP gpplib.GppContainer - wantConsent string - wantError bool - }{ - { - description: "User Consent is not empty", - giveUser: &openrtb2.User{Consent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"}, - wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", - }, - { - description: "User Consent is empty", - giveUser: &openrtb2.User{Consent: ""}, - wantConsent: "", - }, - { - description: "User is nil", - giveUser: nil, - wantConsent: "", - }, - { - description: "User is nil, GPP has no GDPR", - giveUser: nil, - giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}}, - wantConsent: "", - }, - { - description: "User is nil, GPP has GDPR", - giveUser: nil, - giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{2}, Sections: []gpplib.Section{&tcf1Section}}, - wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", - }, - { - description: "User has GDPR, GPP has GDPR", - giveUser: &openrtb2.User{Consent: "BSOMECONSENT"}, - giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{2}, Sections: []gpplib.Section{&tcf1Section}}, - wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - req := openrtb_ext.RequestWrapper{ - BidRequest: &openrtb2.BidRequest{ - User: tt.giveUser, - }, - } - - result, err := getConsent(&req, tt.giveGPP) - assert.Equal(t, tt.wantConsent, result, tt.description) - - if tt.wantError { - assert.NotNil(t, err, tt.description) - } else { - assert.Nil(t, err, tt.description) - } - }) - } -} - -func TestSelectEEACountries(t *testing.T) { - tests := []struct { - description string - hostEEACountries []string - accountEEACountries []string - expected []string - }{ - { - description: "Account_EEA_countries_provided", - hostEEACountries: []string{"UK", "DE"}, - accountEEACountries: []string{"FR", "IT"}, - expected: []string{"FR", "IT"}, - }, - { - description: "Account_is_nil", - hostEEACountries: []string{"UK"}, - accountEEACountries: nil, - expected: []string{"UK"}, - }, - { - description: "Both_nil", - hostEEACountries: nil, - accountEEACountries: nil, - expected: nil, - }, - { - description: "Account_is_empty_slice", - hostEEACountries: []string{"UK"}, - accountEEACountries: []string{}, - expected: []string{}, - }, - { - description: "Host_is_nil", - hostEEACountries: nil, - accountEEACountries: []string{"DE"}, - expected: []string{"DE"}, - }, - { - description: "Host_and_account_both_non-nil", - hostEEACountries: []string{"UK"}, - accountEEACountries: []string{"FR"}, - expected: []string{"FR"}, - }, - { - description: "Host_is_empty_slice,_account_is_nil", - hostEEACountries: []string{}, - accountEEACountries: nil, - expected: []string{}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - result := selectEEACountries(tt.hostEEACountries, tt.accountEEACountries) - assert.Equal(t, tt.expected, result) - }) - } -} - -var upsv1Section mockGPPSection = mockGPPSection{sectionID: 6, value: "1YNY"} -var tcf1Section mockGPPSection = mockGPPSection{sectionID: 2, value: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"} - -type mockGPPSection struct { - sectionID gppConstants.SectionID - value string -} - -func (ms mockGPPSection) GetID() gppConstants.SectionID { - return ms.sectionID -} - -func (ms mockGPPSection) GetValue() string { - return ms.value -} - -func (ms mockGPPSection) Encode(bool) []byte { - return nil -} diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index b3aa91de53..7fe26c4bad 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -145,7 +145,6 @@ func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*op cacheTime: time.Duration(0), gdprPermsBuilder: gdprPermsBuilder, currencyConverter: currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)), - gdprDefaultValue: gdpr.SignalYes, categoriesFetcher: categoriesFetcher, bidIDGenerator: &fakeBidIDGenerator{GenerateBidID: false, ReturnError: false}, } diff --git a/exchange/utils.go b/exchange/utils.go index 08ea0186df..3b88f3d860 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -31,7 +31,7 @@ import ( var errInvalidRequestExt = errors.New("request.ext is invalid") -var channelTypeMap = map[metrics.RequestType]config.ChannelType{ +var ChannelTypeMap = map[metrics.RequestType]config.ChannelType{ metrics.ReqTypeAMP: config.ChannelAMP, metrics.ReqTypeORTB2App: config.ChannelApp, metrics.ReqTypeVideo: config.ChannelVideo, @@ -59,8 +59,6 @@ type requestSplitter struct { func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, auctionReq AuctionRequest, requestExt *openrtb_ext.ExtRequest, - gdprSignal gdpr.Signal, - gdprEnforced bool, bidAdjustmentFactors map[string]float64, ) (bidderRequests []BidderRequest, privacyLabels metrics.PrivacyLabels, errs []error) { req := auctionReq.BidRequestWrapper @@ -115,12 +113,9 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, } } - consent, err := getConsent(req, gpp) - if err != nil { - errs = append(errs, err) - } + consent := gdpr.GetConsent(req, gpp) - ccpaEnforcer, err := extractCCPA(req.BidRequest, rs.privacyConfig, &auctionReq.Account, requestAliases, channelTypeMap[auctionReq.LegacyLabels.RType], gpp) + ccpaEnforcer, err := extractCCPA(req.BidRequest, rs.privacyConfig, &auctionReq.Account, requestAliases, ChannelTypeMap[auctionReq.LegacyLabels.RType], gpp) if err != nil { errs = append(errs, err) } @@ -138,7 +133,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, var gdprPerms gdpr.Permissions = &gdpr.AlwaysAllow{} - if gdprEnforced { + if auctionReq.GDPREnforced { privacyLabels.GDPREnforced = true parsedConsent, err := vendorconsent.ParseString(consent) if err == nil { @@ -149,7 +144,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, gdprRequestInfo := gdpr.RequestInfo{ AliasGVLIDs: requestAliasesGVLIDs, Consent: consent, - GDPRSignal: gdprSignal, + GDPRSignal: auctionReq.GDPRSignal, PublisherID: auctionReq.LegacyLabels.PubID, } gdprPerms = rs.gdprPermsBuilder(auctionReq.TCF2Config, gdprRequestInfo) diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 2898e52b2a..1d1a5c2ac4 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -769,7 +769,7 @@ func TestCleanOpenRTBRequests(t *testing.T) { hostSChainNode: nil, bidderInfo: config.BidderInfos{}, } - bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, map[string]float64{}) if test.hasError { assert.NotNil(t, err, "Error shouldn't be nil") } else { @@ -835,7 +835,7 @@ func TestCleanOpenRTBRequestsWithFPD(t *testing.T) { bidderInfo: config.BidderInfos{}, } - bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, map[string]float64{}) assert.Empty(t, err, "No errors should be returned") for _, bidderRequest := range bidderRequests { bidderName := bidderRequest.BidderName @@ -1158,7 +1158,7 @@ func TestCleanOpenRTBRequestsWithBidResponses(t *testing.T) { bidderInfo: config.BidderInfos{}, } - actualBidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, map[string]float64{}) + actualBidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) assert.Empty(t, err, "No errors should be returned") assert.Len(t, actualBidderRequests, len(test.expectedBidderRequests), "result len doesn't match for testCase %s", test.description) for _, actualBidderRequest := range actualBidderRequests { @@ -1330,7 +1330,7 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) { bidderInfo: config.BidderInfos{}, } - bidderRequests, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) result := bidderRequests[0] assert.Nil(t, errs) @@ -1409,7 +1409,7 @@ func TestCleanOpenRTBRequestsCCPAErrors(t *testing.T) { bidderInfo: config.BidderInfos{}, } - _, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, &reqExtStruct, gdpr.SignalNo, false, map[string]float64{}) + _, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, &reqExtStruct, map[string]float64{}) assert.ElementsMatch(t, []error{test.expectError}, errs, test.description) } @@ -1468,7 +1468,7 @@ func TestCleanOpenRTBRequestsCOPPA(t *testing.T) { bidderInfo: config.BidderInfos{}, } - bidderRequests, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) result := bidderRequests[0] assert.Nil(t, errs) @@ -1629,7 +1629,7 @@ func TestCleanOpenRTBRequestsSChain(t *testing.T) { bidderInfo: config.BidderInfos{"appnexus": config.BidderInfo{OpenRTB: &config.OpenRTBInfo{Version: test.ortbVersion}}}, } - bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, map[string]float64{}) if test.hasError == true { assert.NotNil(t, errs) assert.Len(t, bidderRequests, 0) @@ -1700,7 +1700,7 @@ func TestCleanOpenRTBRequestsBidderParams(t *testing.T) { bidderInfo: config.BidderInfos{}, } - bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, map[string]float64{}) if test.hasError == true { assert.NotNil(t, errs) assert.Len(t, bidderRequests, 0) @@ -2312,7 +2312,7 @@ func TestCleanOpenRTBRequestsLMT(t *testing.T) { bidderInfo: config.BidderInfos{}, } - results, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, map[string]float64{}) + results, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) result := results[0] assert.Nil(t, errs) @@ -2402,6 +2402,8 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) { privacyConfig.GDPR.TCF2, accountConfig.GDPR, ), + GDPRSignal: test.gdprSignal, + GDPREnforced: test.gdprEnforced, } gdprPermissionsBuilder := fakePermissionsBuilder{ @@ -2425,7 +2427,7 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) { bidderInfo: config.BidderInfos{}, } - results, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, test.gdprSignal, test.gdprEnforced, map[string]float64{}) + results, privacyLabels, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) result := results[0] if test.expectError { @@ -2497,6 +2499,7 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) { UserSyncs: &emptyUsersync{}, Account: accountConfig, TCF2Config: gdpr.NewTCF2Config(privacyConfig.GDPR.TCF2, accountConfig.GDPR), + GDPREnforced: test.gdprEnforced, } gdprPermissionsBuilder := fakePermissionsBuilder{ @@ -2520,7 +2523,7 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) { bidderInfo: config.BidderInfos{}, } - results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalYes, test.gdprEnforced, map[string]float64{}) + results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) // extract bidder name from each request in the results bidders := []openrtb_ext.BidderName{} @@ -2607,7 +2610,7 @@ func TestCleanOpenRTBRequestsWithOpenRTBDowngrade(t *testing.T) { hostSChainNode: nil, bidderInfo: test.bidderInfos, } - bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, err := reqSplitter.cleanOpenRTBRequests(context.Background(), test.req, nil, map[string]float64{}) assert.Nil(t, err, "Err should be nil") bidRequest := bidderRequests[0] assert.Equal(t, test.expectRegs, bidRequest.BidRequest.Regs) @@ -3340,7 +3343,7 @@ func TestCleanOpenRTBRequestsSChainMultipleBidders(t *testing.T) { hostSChainNode: nil, bidderInfo: config.BidderInfos{"appnexus": ortb26enabled, "axonix": ortb26enabled}, } - bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, map[string]float64{}) assert.Nil(t, errs) assert.Len(t, bidderRequests, 2, "Bid request count is not 2") @@ -3489,7 +3492,7 @@ func TestCleanOpenRTBRequestsBidAdjustment(t *testing.T) { hostSChainNode: nil, bidderInfo: config.BidderInfos{}, } - results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, test.bidAdjustmentFactor) + results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, test.bidAdjustmentFactor) result := results[0] assert.Nil(t, errs) assert.Equal(t, test.expectedImp, result.BidRequest.Imp, test.description) @@ -3643,7 +3646,7 @@ func TestCleanOpenRTBRequestsBuyerUID(t *testing.T) { }, } - results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, nil) + results, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, nil) assert.Empty(t, errs) for _, v := range results { @@ -4142,7 +4145,7 @@ func TestCleanOpenRTBRequestsFilterBidderRequestExt(t *testing.T) { bidderInfo: config.BidderInfos{}, } - bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, map[string]float64{}) assert.Equal(t, test.wantError, len(errs) != 0, test.desc) sort.Slice(bidderRequests, func(i, j int) bool { return bidderRequests[i].BidderCoreName < bidderRequests[j].BidderCoreName @@ -5283,7 +5286,7 @@ func TestCleanOpenRTBRequestsActivities(t *testing.T) { bidderInfo: config.BidderInfos{"appnexus": config.BidderInfo{OpenRTB: &config.OpenRTBInfo{Version: test.ortbVersion}}}, } - bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo, false, map[string]float64{}) + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) assert.Empty(t, errs) assert.Len(t, bidderRequests, test.expectedReqNumber) diff --git a/gdpr/utils.go b/gdpr/utils.go new file mode 100644 index 0000000000..543b70a4b5 --- /dev/null +++ b/gdpr/utils.go @@ -0,0 +1,95 @@ +package gdpr + +import ( + "strings" + + "github.com/prebid/openrtb/v20/openrtb2" + + gpplib "github.com/prebid/go-gpp" + gppConstants "github.com/prebid/go-gpp/constants" + "github.com/prebid/prebid-server/v3/openrtb_ext" + gppPolicy "github.com/prebid/prebid-server/v3/privacy/gpp" +) + +// GetGDPR will pull the gdpr flag from an openrtb request +func GetGDPR(req *openrtb_ext.RequestWrapper) (Signal, error) { + if req.Regs != nil && len(req.Regs.GPPSID) > 0 { + if gppPolicy.IsSIDInList(req.Regs.GPPSID, gppConstants.SectionTCFEU2) { + return SignalYes, nil + } + return SignalNo, nil + } + if req.Regs != nil && req.Regs.GDPR != nil { + return IntSignalParse(int(*req.Regs.GDPR)) + } + return SignalAmbiguous, nil + +} + +// GetConsent will pull the consent string from an openrtb request +func GetConsent(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) (consent string) { + if i := gppPolicy.IndexOfSID(gpp, gppConstants.SectionTCFEU2); i >= 0 { + return gpp.Sections[i].GetValue() + } + if req.User != nil { + return req.User.Consent + } + return +} + +// EnforceGDPR determines if GDPR should be enforced based on the request signal and whether the channel is enabled +func EnforceGDPR(signal Signal, defaultValue Signal, channelEnabled bool) bool { + gdprApplies := signal == SignalYes || (signal == SignalAmbiguous && defaultValue == SignalYes) + return gdprApplies && channelEnabled +} + +// SelectEEACountries selects the EEA countries based on host and account configurations. +// Account-level configuration takes precedence over the host-level configuration. +func SelectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { + if accountEEACountries != nil { + return accountEEACountries + } + return hostEEACountries +} + +// ParseGDPRDefaultValue determines the default GDPR signal based on the request, configuration, and EEA countries. +func ParseGDPRDefaultValue(r *openrtb_ext.RequestWrapper, cfgDefault string, eeaCountries []string) Signal { + gdprDefaultValue := SignalYes + if cfgDefault == "0" { + gdprDefaultValue = SignalNo + } + + var geo *openrtb2.Geo + if r.User != nil && r.User.Geo != nil { + geo = r.User.Geo + } else if r.Device != nil && r.Device.Geo != nil { + geo = r.Device.Geo + } + + if geo != nil { + // If the country is in the EEA list, GDPR applies. + // Otherwise, if the country code is properly formatted (3 characters), GDPR does not apply. + if isEEACountry(geo.Country, eeaCountries) { + gdprDefaultValue = SignalYes + } else if len(geo.Country) == 3 { + gdprDefaultValue = SignalNo + } + } + + return gdprDefaultValue +} + +// isEEACountry checks if the given country is part of the EEA countries list. +func isEEACountry(country string, eeaCountries []string) bool { + if len(eeaCountries) == 0 { + return false + } + + country = strings.ToUpper(country) + for _, c := range eeaCountries { + if strings.ToUpper(c) == country { + return true + } + } + return false +} diff --git a/gdpr/utils_test.go b/gdpr/utils_test.go new file mode 100644 index 0000000000..01fae95de3 --- /dev/null +++ b/gdpr/utils_test.go @@ -0,0 +1,440 @@ +package gdpr + +import ( + "testing" + + gpplib "github.com/prebid/go-gpp" + gppConstants "github.com/prebid/go-gpp/constants" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/stretchr/testify/assert" +) + +func TestGetGDPR(t *testing.T) { + tests := []struct { + description string + giveRegs *openrtb2.Regs + wantGDPR Signal + wantError bool + }{ + { + description: "Regs Ext GDPR = 0", + giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](0)}, + wantGDPR: SignalNo, + }, + { + description: "Regs Ext GDPR = 1", + giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](1)}, + wantGDPR: SignalYes, + }, + { + description: "Regs Ext GDPR = null", + giveRegs: &openrtb2.Regs{GDPR: nil}, + wantGDPR: SignalAmbiguous, + }, + { + description: "Regs is nil", + giveRegs: nil, + wantGDPR: SignalAmbiguous, + }, + { + description: "Regs Ext GDPR = null, GPPSID has tcf2", + giveRegs: &openrtb2.Regs{GDPR: nil, GPPSID: []int8{2}}, + wantGDPR: SignalYes, + }, + { + description: "Regs Ext GDPR = 1, GPPSID has uspv1", + giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](1), GPPSID: []int8{6}}, + wantGDPR: SignalNo, + }, + { + description: "Regs Ext GDPR = 0, GPPSID has tcf2", + giveRegs: &openrtb2.Regs{GDPR: ptrutil.ToPtr[int8](0), GPPSID: []int8{2}}, + wantGDPR: SignalYes, + }, + { + description: "Regs Ext is nil, GPPSID has tcf2", + giveRegs: &openrtb2.Regs{GPPSID: []int8{2}}, + wantGDPR: SignalYes, + }, + { + description: "Regs Ext is nil, GPPSID has uspv1", + giveRegs: &openrtb2.Regs{GPPSID: []int8{6}}, + wantGDPR: SignalNo, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + req := openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Regs: tt.giveRegs, + }, + } + result, err := GetGDPR(&req) + assert.Equal(t, tt.wantGDPR, result) + + if tt.wantError { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } + }) + } +} + +func TestEnforceGDPR(t *testing.T) { + tests := []struct { + name string + giveSignal Signal + giveDefault Signal + giveChannelFlag bool + wantResult bool + }{ + { + name: "gdpr-applies-with-yes-signal-and-channel-enabled", + giveSignal: SignalYes, + giveDefault: SignalYes, + giveChannelFlag: true, + wantResult: true, + }, + { + name: "gdpr-does-not-apply-with-no-signal-and-channel-enabled", + giveSignal: SignalNo, + giveDefault: SignalYes, + giveChannelFlag: true, + wantResult: false, + }, + { + name: "gdpr-applies-with-ambiguous-signal-and-default-yes-with-channel-enabled", + giveSignal: SignalAmbiguous, + giveDefault: SignalYes, + giveChannelFlag: true, + wantResult: true, + }, + { + name: "gdpr-does-not-apply-with-ambiguous-signal-and-default-no-with-channel-enabled", + giveSignal: SignalAmbiguous, + giveDefault: SignalNo, + giveChannelFlag: true, + wantResult: false, + }, + { + name: "gdpr-does-not-apply-with-yes-signal-and-channel-disabled", + giveSignal: SignalYes, + giveDefault: SignalYes, + giveChannelFlag: false, + wantResult: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := EnforceGDPR(tt.giveSignal, tt.giveDefault, tt.giveChannelFlag) + assert.Equal(t, tt.wantResult, result) + }) + } +} + +func TestGetConsent(t *testing.T) { + tests := []struct { + description string + giveUser *openrtb2.User + giveGPP gpplib.GppContainer + wantConsent string + }{ + { + description: "User Consent is not empty", + giveUser: &openrtb2.User{Consent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"}, + wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", + }, + { + description: "User Consent is empty", + giveUser: &openrtb2.User{Consent: ""}, + wantConsent: "", + }, + { + description: "User is nil", + giveUser: nil, + wantConsent: "", + }, + { + description: "User is nil, GPP has no GDPR", + giveUser: nil, + giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}}, + wantConsent: "", + }, + { + description: "User is nil, GPP has GDPR", + giveUser: nil, + giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{2}, Sections: []gpplib.Section{&tcf1Section}}, + wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", + }, + { + description: "User has GDPR, GPP has GDPR", + giveUser: &openrtb2.User{Consent: "BSOMECONSENT"}, + giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{2}, Sections: []gpplib.Section{&tcf1Section}}, + wantConsent: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA", + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + req := openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: tt.giveUser, + }, + } + + result := GetConsent(&req, tt.giveGPP) + assert.Equal(t, tt.wantConsent, result, tt.description) + }) + } +} + +var upsv1Section mockGPPSection = mockGPPSection{sectionID: 6, value: "1YNY"} +var tcf1Section mockGPPSection = mockGPPSection{sectionID: 2, value: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"} + +type mockGPPSection struct { + sectionID gppConstants.SectionID + value string +} + +func (ms mockGPPSection) GetID() gppConstants.SectionID { + return ms.sectionID +} + +func (ms mockGPPSection) GetValue() string { + return ms.value +} + +func (ms mockGPPSection) Encode(bool) []byte { + return nil +} + +func TestSelectEEACountries(t *testing.T) { + tests := []struct { + description string + hostEEACountries []string + accountEEACountries []string + expected []string + }{ + { + description: "Account_EEA_countries_provided", + hostEEACountries: []string{"UK", "DE"}, + accountEEACountries: []string{"FR", "IT"}, + expected: []string{"FR", "IT"}, + }, + { + description: "Account_is_nil", + hostEEACountries: []string{"UK"}, + accountEEACountries: nil, + expected: []string{"UK"}, + }, + { + description: "Both_nil", + hostEEACountries: nil, + accountEEACountries: nil, + expected: nil, + }, + { + description: "Account_is_empty_slice", + hostEEACountries: []string{"UK"}, + accountEEACountries: []string{}, + expected: []string{}, + }, + { + description: "Host_is_nil", + hostEEACountries: nil, + accountEEACountries: []string{"DE"}, + expected: []string{"DE"}, + }, + { + description: "Host_and_account_both_non-nil", + hostEEACountries: []string{"UK"}, + accountEEACountries: []string{"FR"}, + expected: []string{"FR"}, + }, + { + description: "Host_is_empty_slice,_account_is_nil", + hostEEACountries: []string{}, + accountEEACountries: nil, + expected: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + result := SelectEEACountries(tt.hostEEACountries, tt.accountEEACountries) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestIsEEACountry(t *testing.T) { + eeaCountries := []string{"FRA", "DEU", "ITA", "ESP", "NLD"} + + tests := []struct { + name string + country string + eeaList []string + expected bool + }{ + { + name: "Country_in_EEA", + country: "FRA", + eeaList: eeaCountries, + expected: true, + }, + { + name: "Country_in_EEA_lowercase", + country: "fra", + eeaList: eeaCountries, + expected: true, + }, + { + name: "Country_not_in_EEA", + country: "USA", + eeaList: eeaCountries, + expected: false, + }, + { + name: "Empty_country_string", + country: "", + eeaList: eeaCountries, + expected: false, + }, + { + name: "EEA_list_is_empty", + country: "FRA", + eeaList: []string{}, + expected: false, + }, + { + name: "EEA_list_is_nil", + country: "FRA", + eeaList: nil, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isEEACountry(tt.country, tt.eeaList) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestParseGDPRDefaultValue(t *testing.T) { + tests := []struct { + name string + giveRequest *openrtb_ext.RequestWrapper + giveDefault string + giveEEA []string + wantResult Signal + }{ + { + name: "geo-nil-cfg-default-0", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: nil, + }, + }, + }, + giveDefault: "0", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalNo, + }, + { + name: "user-geo-present-eea-empty", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{Country: "DEU"}, + }, + }, + }, + giveDefault: "0", + giveEEA: []string{}, + wantResult: SignalNo, + }, + { + name: "user-geo-present-geo-country-in-eea", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{Country: "DEU"}, + }, + }, + }, + giveDefault: "0", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalYes, + }, + { + name: "user-geo-present-geo-country-not-in-eea-but-properly-formatted", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{Country: "USA"}, + }, + }, + }, + giveDefault: "1", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalNo, + }, + { + name: "user-geo-present-geo-country-not-in-eea-but-improperly-formatted", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{Country: "US"}, + }, + }, + }, + giveDefault: "1", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalYes, + }, + { + name: "device-geo-present-country-not-in-eea", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Device: &openrtb2.Device{ + Geo: &openrtb2.Geo{Country: "USA"}, + }, + }, + }, + giveDefault: "1", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalNo, + }, + { + name: "user-and-device-geo-present-user-geo-country-selected", + giveRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + User: &openrtb2.User{ + Geo: &openrtb2.Geo{Country: "DEU"}, + }, + Device: &openrtb2.Device{ + Geo: &openrtb2.Geo{Country: "USA"}, + }, + }, + }, + giveDefault: "0", + giveEEA: []string{"DEU", "FRA"}, + wantResult: SignalYes, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ParseGDPRDefaultValue(tt.giveRequest, tt.giveDefault, tt.giveEEA) + assert.Equal(t, tt.wantResult, result) + }) + } +} From 27a1b7ed28cf794ebab24e36350c33fff63486c5 Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Mon, 20 Oct 2025 16:54:13 -0400 Subject: [PATCH 108/272] Actions: Add publish to docker hub workflow (#4558) --- .github/workflows/publishonly.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/publishonly.yml diff --git a/.github/workflows/publishonly.yml b/.github/workflows/publishonly.yml new file mode 100644 index 0000000000..17c2897dda --- /dev/null +++ b/.github/workflows/publishonly.yml @@ -0,0 +1,24 @@ +name: PublishOnly + +on: + workflow_dispatch: + inputs: + imageToPublish: + type: string + required: true + description: 'Already built docker image to publish to docker hub' + + publish-docker-image: + name: Publish docker image + runs-on: ubuntu-latest + steps: + - name: Login to docker Hub + id: login + uses: docker/login-action@v2.1.0 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Publish to docker Hub + if: steps.login.outcome == 'success' + run: | + docker push docker.io/prebid/prebid-server:${{ inputs.imageToPublish }} From 869690d3fd912925e52e737f3f35ac882d9ee1b0 Mon Sep 17 00:00:00 2001 From: Anna Yablonsky <annay@perion.com> Date: Tue, 21 Oct 2025 18:30:45 +0300 Subject: [PATCH 109/272] Omnidex: Add GVL ID (#4568) --- static/bidder-info/omnidex.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/omnidex.yaml b/static/bidder-info/omnidex.yaml index 66d53a2415..321ce19d1f 100644 --- a/static/bidder-info/omnidex.yaml +++ b/static/bidder-info/omnidex.yaml @@ -6,3 +6,4 @@ userSync: iframe: url: https://sync.omni-dex.io/api/user/html/6810d0c7f163277130f3d7a9?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} userMacro: ${userId} +gvlVendorID: 1463 \ No newline at end of file From 749028c572eb327de3e17f2395eae5a806d9229d Mon Sep 17 00:00:00 2001 From: Olivier <osazos@adagio.io> Date: Tue, 21 Oct 2025 17:46:47 +0200 Subject: [PATCH 110/272] Adagio: Fix typo (#4570) --- static/bidder-info/adagio.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/adagio.yaml b/static/bidder-info/adagio.yaml index 3d616d0b5a..c5abf54d35 100644 --- a/static/bidder-info/adagio.yaml +++ b/static/bidder-info/adagio.yaml @@ -1,7 +1,7 @@ # Please deploy this config in each of your datacenters with the appropriate regional subdomain. # Replace the `REGION` by one of the value below: # - For AMER: las => (https://mp-las.4dex.io/pbserver and https://u-las.4dex.io/pbserver/usync.html) -# - For EMEA: ams => (https://mp-ams.4dex.io/pbserver and https://u-amx.4dex.io/pbserver/usync.html) +# - For EMEA: ams => (https://mp-ams.4dex.io/pbserver and https://u-ams.4dex.io/pbserver/usync.html) # - For APAC: tyo => (https://mp-tyo.4dex.io/pbserver and https://u-tyo.4dex.io/pbserver/usync.html) # And set disabled to `false`. endpoint: "https://mp-REGION.4dex.io/pbserver" From 51817ecf79080882e20654f6f58fb746a736f7ac Mon Sep 17 00:00:00 2001 From: Jozef Bartek <31618107+jbartek25@users.noreply.github.com> Date: Tue, 21 Oct 2025 17:58:30 +0200 Subject: [PATCH 111/272] Improve Digital: Switch to HTTPS (#4559) --- static/bidder-info/improvedigital.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/improvedigital.yaml b/static/bidder-info/improvedigital.yaml index cb5ea79807..6dc0e59a8a 100644 --- a/static/bidder-info/improvedigital.yaml +++ b/static/bidder-info/improvedigital.yaml @@ -1,4 +1,4 @@ -endpoint: "http://ad.360yield.com/{PublisherId}pbs" +endpoint: "https://ad.360yield.com/{PublisherId}pbs" maintainer: email: "hb@azerion.com" gvlVendorID: 253 From 2e7ce4b30b0126c20301f4ef51402b1c21cbeb7c Mon Sep 17 00:00:00 2001 From: Marc-Enzo Bonnafon <marcenzo.bonnafon@gmail.com> Date: Wed, 22 Oct 2025 18:53:51 +0100 Subject: [PATCH 112/272] Mobkoi: Update endpoint (#4523) --- static/bidder-info/mobkoi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/mobkoi.yaml b/static/bidder-info/mobkoi.yaml index fcb17c3ba6..7e13df2cc7 100644 --- a/static/bidder-info/mobkoi.yaml +++ b/static/bidder-info/mobkoi.yaml @@ -1,4 +1,4 @@ -endpoint: "https://pbs.maximus.mobkoi.com/bid" +endpoint: "https://pbs.mobkoi.com/bid/prebidserver" maintainer: email: platformteam@mobkoi.com gvlVendorID: 898 From f748b8d831460fb734bf29168543839e8119724a Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 22 Oct 2025 16:45:47 -0400 Subject: [PATCH 113/272] Remove flaky agma test (#4578) --- analytics/agma/agma_module_test.go | 35 ------------------------------ 1 file changed, 35 deletions(-) diff --git a/analytics/agma/agma_module_test.go b/analytics/agma/agma_module_test.go index 25f62d6e9e..61a6e52755 100644 --- a/analytics/agma/agma_module_test.go +++ b/analytics/agma/agma_module_test.go @@ -698,38 +698,3 @@ func TestRaceEnd2End(t *testing.T) { assert.Equal(t, expected, actual) } - -func TestShutdownFlush(t *testing.T) { - cfg := config.AgmaAnalytics{ - Enabled: true, - Endpoint: config.AgmaAnalyticsHttpEndpoint{ - Url: "http://localhost:8000/event", - Timeout: "5s", - }, - Buffers: config.AgmaAnalyticsBuffer{ - EventCount: 1000, - BufferSize: "100mb", - Timeout: "5m", - }, - Accounts: []config.AgmaAnalyticsAccount{ - { - PublisherId: "track-me", - Code: "abc", - }, - }, - } - mockedSender := new(MockedSender) - mockedSender.On("Send", mock.Anything).Return(nil) - clockMock := clock.NewMock() - logger, err := newAgmaLogger(cfg, mockedSender.Send, clockMock) - assert.NoError(t, err) - - go logger.start() - logger.LogAuctionObject(&mockValidAuctionObject) - logger.Shutdown() - - time.Sleep(10 * time.Millisecond) - - mockedSender.AssertCalled(t, "Send", mock.Anything) - mockedSender.AssertNumberOfCalls(t, "Send", 1) -} From 366b71506a2625305e714aaee0eae1df9de8baa5 Mon Sep 17 00:00:00 2001 From: Appstock LTD <sdksupport@app-stock.com> Date: Thu, 23 Oct 2025 16:38:35 +0300 Subject: [PATCH 114/272] New Adapter: appStockSSP (#4502) Co-authored-by: Kanceliarenko <kostiantyn.k@teqblaze.com> --- static/bidder-info/appStockSSP.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 static/bidder-info/appStockSSP.yaml diff --git a/static/bidder-info/appStockSSP.yaml b/static/bidder-info/appStockSSP.yaml new file mode 100644 index 0000000000..a0fbbfb644 --- /dev/null +++ b/static/bidder-info/appStockSSP.yaml @@ -0,0 +1,25 @@ +disabled: true +# We have the following regional endpoint domains: 'lb' - for US_EAST, 'ortb-eu' - for EU, 'ortb-apac' - for APAC +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +aliasOf: "teqblaze" +endpoint: "https://#{REGION}#.al-ad.com/pserver" +maintainer: + email: "sdksupport@app-stock.com" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://csync.al-ad.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://csync.al-ad.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file From 8070000c0040bbac5ab459694c325dcfd152c5af Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Fri, 24 Oct 2025 09:45:54 -0400 Subject: [PATCH 115/272] Rules Engine Module: Dynamic ruleset from YAML geoscopes (#4509) --- config/bidderinfo.go | 36 + config/bidderinfo_test.go | 94 ++ modules/moduledeps/deps.go | 1 + .../rulesengine/bidder_config_ruleset.go | 30 + .../bidder_config_ruleset_builder.go | 288 ++++ .../bidder_config_ruleset_builder_test.go | 1360 +++++++++++++++++ .../rulesengine/bidder_config_ruleset_test.go | 203 +++ modules/prebid/rulesengine/cache_entry.go | 10 +- .../prebid/rulesengine/cache_entry_test.go | 116 +- modules/prebid/rulesengine/config/config.go | 12 +- .../prebid/rulesengine/config/config_test.go | 580 +++---- .../config/rules-engine-schema.json | 20 +- modules/prebid/rulesengine/module.go | 7 +- modules/prebid/rulesengine/module_test.go | 97 ++ modules/prebid/rulesengine/tree_manager.go | 3 +- .../prebid/rulesengine/tree_manager_test.go | 4 +- router/router.go | 18 +- router/router_test.go | 89 ++ 18 files changed, 2656 insertions(+), 312 deletions(-) create mode 100644 modules/prebid/rulesengine/bidder_config_ruleset.go create mode 100644 modules/prebid/rulesengine/bidder_config_ruleset_builder.go create mode 100644 modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go create mode 100644 modules/prebid/rulesengine/bidder_config_ruleset_test.go diff --git a/config/bidderinfo.go b/config/bidderinfo.go index b67ed50825..ff38be125d 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -32,6 +32,7 @@ type BidderInfo struct { Capabilities *CapabilitiesInfo `yaml:"capabilities" mapstructure:"capabilities"` ModifyingVastXmlAllowed bool `yaml:"modifyingVastXmlAllowed" mapstructure:"modifyingVastXmlAllowed"` Debug *DebugInfo `yaml:"debug" mapstructure:"debug"` + Geoscope []string `yaml:"geoscope" mapstructure:"geoscope"` GVLVendorID uint16 `yaml:"gvlVendorID" mapstructure:"gvlVendorID"` Syncer *Syncer `yaml:"userSync" mapstructure:"userSync"` @@ -475,6 +476,9 @@ func validateInfo(bidder BidderInfo, infos BidderInfos, bidderName string) error if err := validateMaintainer(bidder.Maintainer, bidderName); err != nil { return err } + if err := validateGeoscope(bidder.Geoscope, bidderName); err != nil { + return err + } if err := validateCapabilities(bidder.Capabilities, bidderName); err != nil { return err } @@ -591,6 +595,38 @@ func validatePlatformInfo(info *PlatformInfo) error { return nil } +func validateGeoscope(geoscope []string, bidderName string) error { + // ISO 3166-1 alpha-3 country codes are uppercase 3-letter codes + for i, code := range geoscope { + code = strings.ToUpper(strings.TrimSpace(code)) + + if code == "GLOBAL" || code == "EEA" { + continue + } + + // Handle exclusion pattern with "!" prefix + exclusion := "" + if strings.HasPrefix(code, "!") { + exclusion = "!" + code = code[1:] + } + + if len(code) != 3 { + return fmt.Errorf("invalid geoscope entry at index %d: %s for adapter: %s%s - must be a 3-letter ISO 3166-1 alpha-3 country code", + i, code, exclusion, bidderName) + } + + for _, char := range code { + if char < 'A' || char > 'Z' { + return fmt.Errorf("invalid geoscope entry at index %d: %s for adapter: %s%s - must contain only uppercase letters A-Z", + i, code, exclusion, bidderName) + } + } + } + + return nil +} + func validateSyncer(bidderInfo BidderInfo) error { if bidderInfo.Syncer == nil { return nil diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index e2270ed2f9..41f9687850 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -2008,3 +2008,97 @@ func TestReadFullYamlBidderConfig(t *testing.T) { } assert.Equalf(t, expectedBidderInfo, actualBidderInfo, "Bidder info objects aren't matching") } + +func TestValidateGeoscope(t *testing.T) { + testCases := []struct { + name string + geoscope []string + bidderName string + expectErr bool + errMsg string + }{ + { + name: "nil", + geoscope: nil, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "empty", + geoscope: []string{}, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "valid-iso-code", + geoscope: []string{"USA"}, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "valid-with-global-and-eea", + geoscope: []string{"USA", "GLOBAL", "EEA"}, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "valid-with-exclusion", + geoscope: []string{"!USA"}, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "mixed-case-valid", + geoscope: []string{"UsA", "can", "GbR"}, + bidderName: "testBidder", + expectErr: false, + }, + { + name: "invalid-length", + geoscope: []string{"USAA"}, + bidderName: "testBidder", + expectErr: true, + errMsg: "invalid geoscope entry at index 0: USAA for adapter: testBidder - must be a 3-letter ISO 3166-1 alpha-3 country code", + }, + { + name: "invalid-exclusion-length", + geoscope: []string{"!USAA"}, + bidderName: "testBidder", + expectErr: true, + errMsg: "invalid geoscope entry at index 0: USAA for adapter: !testBidder - must be a 3-letter ISO 3166-1 alpha-3 country code", + }, + { + name: "non-letter-characters", + geoscope: []string{"US1"}, + bidderName: "testBidder", + expectErr: true, + errMsg: "invalid geoscope entry at index 0: US1 for adapter: testBidder - must contain only uppercase letters A-Z", + }, + { + name: "too-short-code", + geoscope: []string{"US"}, + bidderName: "testBidder", + expectErr: true, + errMsg: "invalid geoscope entry at index 0: US for adapter: testBidder - must be a 3-letter ISO 3166-1 alpha-3 country code", + }, + { + name: "whitespace-and-trimming", + geoscope: []string{" USA "}, + bidderName: "testBidder", + expectErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateGeoscope(tc.geoscope, tc.bidderName) + + if tc.expectErr { + assert.Error(t, err) + assert.Contains(t, err.Error(), tc.errMsg) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/modules/moduledeps/deps.go b/modules/moduledeps/deps.go index 266e22575e..a60587e1ef 100644 --- a/modules/moduledeps/deps.go +++ b/modules/moduledeps/deps.go @@ -11,4 +11,5 @@ import ( type ModuleDeps struct { HTTPClient *http.Client RateConvertor *currency.RateConverter + Geoscope map[string][]string } diff --git a/modules/prebid/rulesengine/bidder_config_ruleset.go b/modules/prebid/rulesengine/bidder_config_ruleset.go new file mode 100644 index 0000000000..888c41c696 --- /dev/null +++ b/modules/prebid/rulesengine/bidder_config_ruleset.go @@ -0,0 +1,30 @@ +package rulesengine + +import ( + "github.com/prebid/prebid-server/v3/rules" +) + +// buildBidderConfigRuleSet builds a dynamic ruleset based on the geoscope annotations in the +// static bidder-info bidder YAML files +func buildBidderConfigRuleSet(geoscopes map[string][]string, setDefinitions map[string][]string) ([]cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult], error) { + crs := cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult]{ + name: "Dynamic ruleset from geoscopes", + modelGroups: []cacheModelGroup[RequestWrapper, ProcessedAuctionHookResult]{ + { + weight: 100, + version: "1.0", + analyticsKey: "bidderConfig", + }, + }, + } + + builder := NewBidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult](geoscopes, setDefinitions) + + tree, err := rules.NewTree[RequestWrapper, ProcessedAuctionHookResult](builder) + if err != nil { + return nil, err + } + crs.modelGroups[0].tree = *tree + + return []cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult]{crs}, nil +} diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_builder.go b/modules/prebid/rulesengine/bidder_config_ruleset_builder.go new file mode 100644 index 0000000000..2fe9b705c6 --- /dev/null +++ b/modules/prebid/rulesengine/bidder_config_ruleset_builder.go @@ -0,0 +1,288 @@ +package rulesengine + +import ( + "encoding/json" + "errors" + "slices" + "strings" + + "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v3/rules" +) + +type CountryExclusions = map[string][]string +type CountryGroups = map[string][]string + +// defaultCountryGroups maps country group names to their member countries +var defaultCountryGroups = CountryGroups{ + "EEA": []string{ + "AUT", "BEL", "BGR", "CYP", "CZE", "DEU", "DNK", "EST", "ESP", + "FIN", "FRA", "GRC", "HRV", "HUN", "IRL", "ISL", "ITA", "LIE", + "LTU", "LUX", "LVA", "MLT", "NLD", "NOR", "POL", "PRT", "ROU", + "SWE", "SVN", "SVK", + }, +} + +// parsedConfig holds the parsed geoscope configuration for a bidder +type parsedConfig struct { + bidder string + globalIncluded bool + countryGroupsIncluded []string + countryGroupsExcluded []string + singleCountriesIncluded []string + singleCountriesExcluded []string +} + +// NewBidderConfigRuleSetBuilder creates a new instance of bidderConfigRuleSetBuilder +func NewBidderConfigRuleSetBuilder[T1 RequestWrapper, T2 ProcessedAuctionHookResult]( + geoscopeConfig map[string][]string, setDefinitions map[string][]string, +) *bidderConfigRuleSetBuilder[T1, T2] { + + return &bidderConfigRuleSetBuilder[T1, T2]{ + countryGroups: mergeCountryGroups(defaultCountryGroups, setDefinitions), + geoscopeConfig: geoscopeConfig, + } +} + +// mergeCountryGroups merges the default country groups with any account-defined set definitions +func mergeCountryGroups(defaults, setDefinitions CountryGroups) CountryGroups { + countryGroups := make(CountryGroups, len(defaults)) + for k, v := range defaults { + copied := make([]string, len(v)) + copy(copied, v) + countryGroups[strings.ToUpper(k)] = copied + } + for k, v := range setDefinitions { + copied := make([]string, len(v)) + copy(copied, v) + countryGroups[strings.ToUpper(k)] = copied + } + return countryGroups +} + +// bidderConfigRuleSetBuilder builds a dynamic rule set based on the geoscope annotations in the +// static bidder-info bidder YAML files +type bidderConfigRuleSetBuilder[T1 RequestWrapper, T2 ProcessedAuctionHookResult] struct { + countryGroups CountryGroups + geoscopeConfig map[string][]string +} + +// Build constructs the dynamic rule set +func (b *bidderConfigRuleSetBuilder[T1, T2]) Build(tree *rules.Tree[RequestWrapper, ProcessedAuctionHookResult]) error { + if len(b.geoscopeConfig) == 0 || tree.Root == nil { + return nil + } + + schemaFunc, err := rules.NewDeviceCountry(json.RawMessage(`{}`)) + if err != nil { + return err + } + tree.Root.SchemaFunction = schemaFunc + + countryExclusions := b.initializeCountryExclusions() + + for bidder, geoscopes := range b.geoscopeConfig { + parsedCfg, err := b.parseBidderGeoscopes(bidder, geoscopes) + if err != nil { + return err + } + + if parsedCfg.globalIncluded { + continue + } else if len(parsedCfg.countryGroupsIncluded) > 0 { + b.markAllowListWithGroupsExclusions(parsedCfg, countryExclusions) + } else if len(parsedCfg.countryGroupsExcluded) > 0 { + b.markBlockListWithGroupsExclusions(parsedCfg, countryExclusions) + } else if len(parsedCfg.singleCountriesIncluded) > 0 { + b.markAllowListExclusions(parsedCfg, countryExclusions) + } else if len(parsedCfg.singleCountriesExcluded) > 0 { + b.markBlockListExclusions(parsedCfg, countryExclusions) + } + } + + addTreeNodes(tree.Root, countryExclusions) + + return nil +} + +// populateCountries creates a exclusions map with its set of keys being all geoscope annotation countries explicitly +// called out along with all countries in a geoscope annotation country group +// The bidder exclusions for each country is empty +func (b *bidderConfigRuleSetBuilder[T1, T2]) initializeCountryExclusions() CountryExclusions { + + countryExclusions := map[string][]string{} + countryGroupsSeen := map[string]struct{}{} + + for _, geoscopes := range b.geoscopeConfig { + for _, geoscope := range geoscopes { + if geoscope == "GLOBAL" { + continue + } + if strings.HasPrefix(geoscope, "!") { + geoscope = strings.TrimPrefix(geoscope, "!") + } + if countryGroup, groupFound := b.countryGroups[geoscope]; groupFound { + if _, countrySeen := countryGroupsSeen[geoscope]; !countrySeen { + for _, country := range countryGroup { + if _, exists := countryExclusions[country]; !exists { + countryExclusions[country] = []string{} + } + } + countryGroupsSeen[geoscope] = struct{}{} + } + } else if _, exists := countryExclusions[geoscope]; !exists { + countryExclusions[geoscope] = []string{} + } + } + } + countryExclusions["*"] = []string{} + + return countryExclusions +} + +// parseBidderGeoscopes parses the geoscope directives for a bidder and returns a parsedConfig struct +func (b *bidderConfigRuleSetBuilder[T1, T2]) parseBidderGeoscopes(bidder string, geoscopes []string) (parsedConfig, error) { + cfg := parsedConfig{bidder: bidder} + + for _, geoscope := range geoscopes { + if geoscope == "GLOBAL" { + cfg.globalIncluded = true + } else if b.includedCountryGroup(geoscope) { + cfg.countryGroupsIncluded = append(cfg.countryGroupsIncluded, geoscope) + } else if b.excludedCountryGroup(geoscope) { + cfg.countryGroupsExcluded = append(cfg.countryGroupsExcluded, strings.TrimPrefix(geoscope, "!")) + } else if b.includedSingleCountry(geoscope) { + cfg.singleCountriesIncluded = append(cfg.singleCountriesIncluded, geoscope) + } else if b.excludedSingleCountry(geoscope) { + cfg.singleCountriesExcluded = append(cfg.singleCountriesExcluded, strings.TrimPrefix(geoscope, "!")) + } else { + return cfg, errors.New("unknown geoscope type: " + geoscope) + } + } + + return cfg, nil +} + +// markAllowListWithGroupsExclusions analyzes the parsed bidder config to determine which countries should be excluded. +// It is called when it has been determined that the bidder geoscope information should be interpreted as +// an allow list and there is at least one allowed country group specified in the geoscope directives for +// the bidder. +func (b *bidderConfigRuleSetBuilder[T1, T2]) markAllowListWithGroupsExclusions(cfg parsedConfig, countryExclusions CountryExclusions) { + for country, excludedBidders := range countryExclusions { + inGroup := b.countryInAGroup(country, cfg.countryGroupsIncluded) + specificallyIncluded := slices.Contains(cfg.singleCountriesIncluded, country) + specificallyExcluded := slices.Contains(cfg.singleCountriesExcluded, country) + + if inGroup && specificallyExcluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } else if !inGroup && !specificallyIncluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } + } +} + +// markBlockListWithGroupsExclusions analyzes the parsed bidder config to determine which countries should be excluded. +// It is called when it has been determined that the bidder geoscope information should be interpreted as +// a block list and there is at least one blocked country group specified in the geoscope directives for +// the bidder. +func (b *bidderConfigRuleSetBuilder[T1, T2]) markBlockListWithGroupsExclusions(cfg parsedConfig, countryExclusions CountryExclusions) { + for country, excludedBidders := range countryExclusions { + inGroup := b.countryInAGroup(country, cfg.countryGroupsExcluded) + specificallyIncluded := slices.Contains(cfg.singleCountriesIncluded, country) + specificallyExcluded := slices.Contains(cfg.singleCountriesExcluded, country) + + if inGroup && !specificallyIncluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } else if !inGroup && specificallyExcluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } + } +} + +// markAllowListExclusions analyzes the parsed bidder config to determine which countries should be excluded. +// It is called when it has been determined that the bidder geoscope information should be interpreted as +// an allow list and there are no country groups specified in the geoscope directives for the bidder. +func (b *bidderConfigRuleSetBuilder[T1, T2]) markAllowListExclusions(cfg parsedConfig, countryExclusions CountryExclusions) { + for country, excludedBidders := range countryExclusions { + specificallyIncluded := slices.Contains(cfg.singleCountriesIncluded, country) + + if !specificallyIncluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } + } +} + +// markBlockListExclusions analyzes the parsed bidder config to determine which countries should be excluded. +// It is called when it has been determined that the bidder geoscope information should be interpreted as +// a block list and there are no country groups specified in the geoscope directives for the bidder. +func (b *bidderConfigRuleSetBuilder[T1, T2]) markBlockListExclusions(cfg parsedConfig, countryExclusions CountryExclusions) { + for country, excludedBidders := range countryExclusions { + specificallyExcluded := slices.Contains(cfg.singleCountriesExcluded, country) + + if specificallyExcluded { + excludedBidders = append(excludedBidders, cfg.bidder) + countryExclusions[country] = excludedBidders + } + } +} + +// includeCountryGroup checks if the geoscope annotation refers to an included country group +func (b *bidderConfigRuleSetBuilder[T1, T2]) includedCountryGroup(geoscope string) bool { + return b.countryGroups[geoscope] != nil +} + +// excludedCountryGroup checks if the geoscope annotation refers to an excluded country group +func (b *bidderConfigRuleSetBuilder[T1, T2]) excludedCountryGroup(geoscope string) bool { + return strings.HasPrefix(geoscope, "!") && b.countryGroups[geoscope[1:]] != nil +} + +// includedSingleCountry checks if the geoscope annotation refers to an included country +func (b *bidderConfigRuleSetBuilder[T1, T2]) includedSingleCountry(geoscope string) bool { + return !strings.HasPrefix(geoscope, "!") && b.countryGroups[geoscope] == nil +} + +// excludedSingleCountry checks if the geoscope annotation refers to an excluded country +func (b *bidderConfigRuleSetBuilder[T1, T2]) excludedSingleCountry(geoscope string) bool { + return strings.HasPrefix(geoscope, "!") && b.countryGroups[geoscope] == nil +} + +// countryInAGroup checks if the given country is part of any of the specified country groups +func (b *bidderConfigRuleSetBuilder[T1, T2]) countryInAGroup(country string, groups []string) bool { + for _, groupName := range groups { + if countryList, exists := b.countryGroups[groupName]; exists { + for _, countryInGroup := range countryList { + if country == countryInGroup { + return true + } + } + } + } + return false +} + +// addTreeNodes adds the country exclusion nodes to the rules tree +func addTreeNodes(root *rules.Node[RequestWrapper, ProcessedAuctionHookResult], countryExclusions CountryExclusions) { + root.Children = make(map[string]*rules.Node[RequestWrapper, ProcessedAuctionHookResult]) + + for country, excludedBidders := range countryExclusions { + + node := rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + SchemaFunction: nil, + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: excludedBidders, + }, + }, + }, + Children: nil, + } + + root.Children[country] = &node + } +} diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go b/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go new file mode 100644 index 0000000000..e9f9743aff --- /dev/null +++ b/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go @@ -0,0 +1,1360 @@ +package rulesengine + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/rules" + "github.com/stretchr/testify/assert" +) + +func TestMergeCountryGroups(t *testing.T) { + defaultCountryGroups := CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "north_america": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + } + + testCases := []struct { + name string + defaults CountryGroups + setDefinitions CountryGroups + expected CountryGroups + }{ + { + name: "nil-set-definitions", + defaults: defaultCountryGroups, + setDefinitions: nil, + expected: CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + }, + }, + { + name: "empty-set-definitions", + defaults: defaultCountryGroups, + setDefinitions: CountryGroups{}, + expected: CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + }, + }, + { + name: "override-existing-group", + defaults: defaultCountryGroups, + setDefinitions: CountryGroups{ + "EEA": []string{"ESP", "PRT", "GRC"}, + }, + expected: CountryGroups{ + "EEA": []string{"ESP", "PRT", "GRC"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + }, + }, + { + name: "add-new-group", + defaults: defaultCountryGroups, + setDefinitions: CountryGroups{ + "asia": []string{"JPN", "KOR", "CHN"}, + }, + expected: CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "ASIA": []string{"JPN", "KOR", "CHN"}, + }, + }, + { + name: "empty-defaults", + defaults: CountryGroups{}, + setDefinitions: CountryGroups{ + "asia": []string{"JPN", "KOR", "CHN"}, + }, + expected: CountryGroups{ + "ASIA": []string{"JPN", "KOR", "CHN"}, + }, + }, + { + name: "multiple-operations", + defaults: defaultCountryGroups, + setDefinitions: CountryGroups{ + "eea": []string{"ESP", "PRT"}, + "asia": []string{"JPN", "KOR"}, + "africa": []string{"ZAF", "EGY", "NGA"}, + }, + expected: CountryGroups{ + "EEA": []string{"ESP", "PRT"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "ASIA": []string{"JPN", "KOR"}, + "AFRICA": []string{"ZAF", "EGY", "NGA"}, + }, + }, + { + name: "empty-slice-in-set-definitions", + defaults: defaultCountryGroups, + setDefinitions: CountryGroups{ + "empty_group": []string{}, + }, + expected: CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "EMPTY_GROUP": []string{}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := mergeCountryGroups(tc.defaults, tc.setDefinitions) + + assert.Len(t, result, len(tc.expected), "Result should have the expected number of groups") + + for groupName, expectedCountries := range tc.expected { + actualCountries, exists := result[groupName] + assert.True(t, exists, "Group %s should exist in result", groupName) + assert.ElementsMatch(t, expectedCountries, actualCountries) + } + }) + } +} + +func TestBuild(t *testing.T) { + // Define test groups + testCountryGroups := CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + } + + testCases := []struct { + name string + geoscopeConfig map[string][]string + countryGroups CountryGroups + nilRoot bool + expectError bool + expectedKeys map[string][]string + }{ + { + name: "empty-geoscope-config", + geoscopeConfig: map[string][]string{}, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: nil, + }, + { + name: "nil-root-node", + geoscopeConfig: map[string][]string{"bidder1": {"USA"}}, + countryGroups: testCountryGroups, + nilRoot: true, + expectError: false, + expectedKeys: nil, + }, + { + name: "global-directive-only", + geoscopeConfig: map[string][]string{ + "bidder1": {"GLOBAL"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {}, + }, + }, + { + name: "allow-list-with-groups", + geoscopeConfig: map[string][]string{ + "bidder1": {"NORTH_AMERICA"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {"bidder1"}, + "USA": {}, + "CAN": {}, + "MEX": {}, + }, + }, + { + name: "block-list-with-groups", + geoscopeConfig: map[string][]string{ + "bidder1": {"!NORTH_AMERICA"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {}, + "USA": {"bidder1"}, + "CAN": {"bidder1"}, + "MEX": {"bidder1"}, + }, + }, + { + name: "allow-list-with-specific-countries", + geoscopeConfig: map[string][]string{ + "bidder1": {"ESP", "GBR"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {"bidder1"}, + "ESP": {}, + "GBR": {}, + }, + }, + { + name: "block-list-with-specific-countries", + geoscopeConfig: map[string][]string{ + "bidder1": {"!ESP", "!GBR"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {}, + "ESP": {"bidder1"}, + "GBR": {"bidder1"}, + }, + }, + { + name: "multiple-bidders-with-different-scopes", + geoscopeConfig: map[string][]string{ + "bidder1": {"NORTH_AMERICA"}, + "bidder2": {"!EEA"}, + "bidder3": {"ESP", "GBR"}, + "bidder4": {"!JPN"}, + }, + countryGroups: testCountryGroups, + nilRoot: false, + expectError: false, + expectedKeys: map[string][]string{ + "*": {"bidder1", "bidder3"}, + "USA": {"bidder3"}, + "CAN": {"bidder3"}, + "MEX": {"bidder3"}, + "FRA": {"bidder1", "bidder2", "bidder3"}, + "DEU": {"bidder1", "bidder2", "bidder3"}, + "ITA": {"bidder1", "bidder2", "bidder3"}, + "ESP": {"bidder1"}, + "GBR": {"bidder1"}, + "JPN": {"bidder1", "bidder3", "bidder4"}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a tree + tree := &rules.Tree[RequestWrapper, ProcessedAuctionHookResult]{ + Root: nil, + } + + if !tc.nilRoot { + tree.Root = &rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + Children: make(map[string]*rules.Node[RequestWrapper, ProcessedAuctionHookResult]), + } + } + + // Create the builder + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{ + countryGroups: tc.countryGroups, + geoscopeConfig: tc.geoscopeConfig, + } + + // Call the Build function + err := builder.Build(tree) + + // Check for expected error + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + + if tc.nilRoot { + assert.Nil(t, tree.Root) + } else if len(tc.geoscopeConfig) == 0 { + assert.Nil(t, tree.Root.SchemaFunction) + assert.Len(t, tree.Root.Children, 0) + } else { + assert.NotNil(t, tree.Root.SchemaFunction) + assert.Equal(t, len(tc.expectedKeys), len(tree.Root.Children)) + + for k, v := range tc.expectedKeys { + childNode, ok := tree.Root.Children[k] + assert.True(t, ok, "Expected child node %q to be present", k) + assert.Len(t, childNode.ResultFunctions, 1) + assert.IsType(t, &ExcludeBidders{}, childNode.ResultFunctions[0]) + assert.ElementsMatch(t, v, childNode.ResultFunctions[0].(*ExcludeBidders).Args.Bidders) + } + } + }) + } +} + +func TestInitializeCountryExclusions(t *testing.T) { + // Define test groups + testCountryGroups := CountryGroups{ + "TEST_GROUP1": []string{"USA", "CAN", "MEX"}, + "TEST_GROUP2": []string{"FRA", "DEU", "ITA"}, + "EMPTY_GROUP": []string{}, + } + + testCases := []struct { + name string + countryGroups CountryGroups + geoscopeConfig map[string][]string + expected CountryExclusions + }{ + { + name: "empty-geoscope-config", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{}, + expected: CountryExclusions{ + "*": []string{}, + }, + }, + { + name: "nil-geoscope-config", + countryGroups: testCountryGroups, + geoscopeConfig: nil, + expected: CountryExclusions{ + "*": []string{}, + }, + }, + { + name: "single-country-code", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"USA"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "*": []string{}, + }, + }, + { + name: "multiple-country-codes", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"USA", "CAN", "MEX"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "*": []string{}, + }, + }, + { + name: "country-group-expands-to-countries", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"TEST_GROUP1"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "*": []string{}, + }, + }, + { + name: "excluded-country-code", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"!USA"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "*": []string{}, + }, + }, + { + name: "excluded-country-group-expands-to-countries", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"!TEST_GROUP1"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "*": []string{}, + }, + }, + { + name: "mix-of-countries-and-groups", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"TEST_GROUP1", "FRA"}, + "bidder2": {"!TEST_GROUP2", "USA"}, + "bidder3": {"ESP", "JAP"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "FRA": []string{}, + "DEU": []string{}, + "ITA": []string{}, + "ESP": []string{}, + "JAP": []string{}, + "*": []string{}, + }, + }, + { + name: "global-directive-is-skipped", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"GLOBAL", "USA"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "*": []string{}, + }, + }, + { + name: "empty-group-not-expanded", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"EMPTY_GROUP"}, + }, + expected: CountryExclusions{ + "*": []string{}, + }, + }, + { + name: "multiple-bidders-same-countries", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"USA", "CAN"}, + "bidder2": {"USA", "MEX"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "*": []string{}, + }, + }, + { + name: "group-only-expanded-once-when-used-multiple-times", + countryGroups: testCountryGroups, + geoscopeConfig: map[string][]string{ + "bidder1": {"TEST_GROUP1"}, + "bidder2": {"TEST_GROUP1"}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "MEX": []string{}, + "*": []string{}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{ + countryGroups: tc.countryGroups, + geoscopeConfig: tc.geoscopeConfig, + } + + result := builder.initializeCountryExclusions() + + // Check keys are the same (regardless of order) + expectedKeys := make([]string, 0, len(tc.expected)) + for k := range tc.expected { + expectedKeys = append(expectedKeys, k) + } + + resultKeys := make([]string, 0, len(result)) + for k := range result { + resultKeys = append(resultKeys, k) + } + + assert.ElementsMatch(t, expectedKeys, resultKeys) + + // Check all expected keys have empty exclusion lists + for country, excludedBidders := range result { + assert.Empty(t, excludedBidders, "Country %s should have empty exclusion list", country) + } + }) + } +} + +func TestParseBidderGeoscopes(t *testing.T) { + // Define test groups + testCountryGroups := CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "BALTIC": []string{"EST", "LVA", "LTU"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + } + + testCases := []struct { + name string + bidder string + geoscopes []string + expected parsedConfig + expectError bool + }{ + { + name: "nil-geoscopes", + bidder: "bidder1", + geoscopes: nil, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: nil, + countryGroupsExcluded: nil, + singleCountriesIncluded: nil, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "empty-geoscopes", + bidder: "bidder1", + geoscopes: []string{}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: nil, + countryGroupsExcluded: nil, + singleCountriesIncluded: nil, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "global-scope", + bidder: "bidder1", + geoscopes: []string{"GLOBAL"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: true, + countryGroupsIncluded: nil, + countryGroupsExcluded: nil, + singleCountriesIncluded: nil, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "included-country-group", + bidder: "bidder1", + geoscopes: []string{"NORTH_AMERICA"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + countryGroupsExcluded: nil, + singleCountriesIncluded: nil, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "excluded-country-group", + bidder: "bidder1", + geoscopes: []string{"!NORTH_AMERICA"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: nil, + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: nil, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "included-single-country", + bidder: "bidder1", + geoscopes: []string{"ESP"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: nil, + countryGroupsExcluded: nil, + singleCountriesIncluded: []string{"ESP"}, + singleCountriesExcluded: nil, + }, + expectError: false, + }, + { + name: "excluded-single-country", + bidder: "bidder1", + geoscopes: []string{"!ESP"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: false, + countryGroupsIncluded: nil, + countryGroupsExcluded: nil, + singleCountriesIncluded: nil, + singleCountriesExcluded: []string{"ESP"}, + }, + expectError: false, + }, + { + name: "mixed-multiple-geoscopes", + bidder: "bidder1", + geoscopes: []string{"GLOBAL", "NORTH_AMERICA", "NORDIC", "!BALTIC", "!EEA", "ESP", "!FRA", "BRA", "!ARG"}, + expected: parsedConfig{ + bidder: "bidder1", + globalIncluded: true, + countryGroupsIncluded: []string{"NORTH_AMERICA", "NORDIC"}, + countryGroupsExcluded: []string{"BALTIC", "EEA"}, + singleCountriesIncluded: []string{"ESP", "BRA"}, + singleCountriesExcluded: []string{"FRA", "ARG"}, + }, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{ + countryGroups: testCountryGroups, + } + + result, err := builder.parseBidderGeoscopes(tc.bidder, tc.geoscopes) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + + assert.Equal(t, tc.expected.bidder, result.bidder) + assert.Equal(t, tc.expected.globalIncluded, result.globalIncluded) + assert.ElementsMatch(t, tc.expected.countryGroupsIncluded, result.countryGroupsIncluded) + assert.ElementsMatch(t, tc.expected.countryGroupsExcluded, result.countryGroupsExcluded) + assert.ElementsMatch(t, tc.expected.singleCountriesIncluded, result.singleCountriesIncluded) + assert.ElementsMatch(t, tc.expected.singleCountriesExcluded, result.singleCountriesExcluded) + } + }) + } +} + +func TestMarkAllowListWithGroupsExclusions(t *testing.T) { + // Define test groups + testCountryGroups := CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "BALTIC": []string{"EST", "LVA", "LTU"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + } + + testCases := []struct { + name string + config parsedConfig + countryExclusions CountryExclusions + expected CountryExclusions + }{ + { + name: "country-in-group-not-excluded", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{"bidder1"}, + "JPN": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "country-in-group-specifically-excluded", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{}, + "GBR": []string{"bidder1"}, + "JPN": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "country-not-in-group-specifically-included", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{"GBR"}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "multiple-included-groups", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA", "EEA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "FRA": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "FRA": []string{}, + "JPN": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "multiple-bidders-in-exclusions", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "GBR": []string{"existing-bidder"}, + }, + expected: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "GBR": []string{"existing-bidder", "bidder1"}, + }, + }, + { + name: "empty-country-exclusions", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsIncluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{}, + expected: CountryExclusions{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{ + countryGroups: testCountryGroups, + } + + builder.markAllowListWithGroupsExclusions(tc.config, tc.countryExclusions) + + // Check that all expected keys exist with the right values + for country, expectedBidders := range tc.expected { + assert.ElementsMatch(t, expectedBidders, tc.countryExclusions[country], + "Country %s should have the expected excluded bidders", country) + } + + // Check that there are no unexpected keys + assert.Equal(t, len(tc.expected), len(tc.countryExclusions), + "Expected and actual CountryExclusions should have the same number of entries") + }) + } +} + +func TestMarkBlockListWithGroupsExclusions(t *testing.T) { + // Define test groups + testCountryGroups := CountryGroups{ + "EEA": []string{"FRA", "DEU", "ITA"}, + "BALTIC": []string{"EST", "LVA", "LTU"}, + "NORDIC": []string{"FIN", "NOR", "SWE"}, + "NORTH_AMERICA": []string{"USA", "CAN", "MEX"}, + } + + testCases := []struct { + name string + config parsedConfig + countryExclusions CountryExclusions + expected CountryExclusions + }{ + { + name: "country-in-excluded-group-excluded", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + }, + { + name: "country-in-excluded-group-specifically-included", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{"USA"}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{"bidder1"}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + }, + { + name: "country-not-in-excluded-group-specifically-excluded", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{"GBR"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{"bidder1"}, + "JPN": []string{}, + "*": []string{}, + }, + }, + { + name: "multiple-excluded-groups", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA", "EEA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "FRA": []string{}, + "JPN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "FRA": []string{"bidder1"}, + "JPN": []string{}, + "*": []string{}, + }, + }, + { + name: "multiple-bidders-in-exclusions", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "GBR": []string{"existing-bidder"}, + }, + expected: CountryExclusions{ + "USA": []string{"existing-bidder", "bidder1"}, + "GBR": []string{"existing-bidder"}, + }, + }, + { + name: "country-in-excluded-group-with-specific-exclusion", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "*": []string{}, + }, + }, + { + name: "empty-country-exclusions", + config: parsedConfig{ + bidder: "bidder1", + countryGroupsExcluded: []string{"NORTH_AMERICA"}, + singleCountriesIncluded: []string{}, + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{}, + expected: CountryExclusions{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{ + countryGroups: testCountryGroups, + } + + builder.markBlockListWithGroupsExclusions(tc.config, tc.countryExclusions) + + // Check that all expected keys exist with the right values + for country, expectedBidders := range tc.expected { + assert.ElementsMatch(t, expectedBidders, tc.countryExclusions[country], + "Country %s should have the expected excluded bidders", country) + } + + // Check that there are no unexpected keys + assert.Equal(t, len(tc.expected), len(tc.countryExclusions), + "Expected and actual CountryExclusions should have the same number of entries") + }) + } +} + +func TestMarkAllowListExclusions(t *testing.T) { + testCases := []struct { + name string + config parsedConfig + countryExclusions CountryExclusions + expected CountryExclusions + }{ + { + name: "single-country-included", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{"bidder1"}, + "GBR": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "multiple-countries-included", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"USA", "CAN"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "no-countries-included", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "existing-excluded-bidders-preserved", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "CAN": []string{"existing-bidder"}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "CAN": []string{"existing-bidder", "bidder1"}, + "GBR": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + { + name: "empty-country-exclusions", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{}, + expected: CountryExclusions{}, + }, + { + name: "specifically-included-wildcard", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"*"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{"bidder1"}, + "*": []string{}, + }, + }, + { + name: "country-not-in-exclusions-map", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesIncluded: []string{"BRA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{"bidder1"}, + "*": []string{"bidder1"}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{} + + builder.markAllowListExclusions(tc.config, tc.countryExclusions) + + // Check that all expected keys exist with the right values + for country, expectedBidders := range tc.expected { + assert.ElementsMatch(t, expectedBidders, tc.countryExclusions[country], + "Country %s should have the expected excluded bidders", country) + } + + // Check that there are no unexpected keys + assert.Equal(t, len(tc.expected), len(tc.countryExclusions), + "Expected and actual CountryExclusions should have the same number of entries") + }) + } +} + +func TestMarkBlockListExclusions(t *testing.T) { + testCases := []struct { + name string + config parsedConfig + countryExclusions CountryExclusions + expected CountryExclusions + }{ + { + name: "single-country-excluded", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + }, + { + name: "multiple-countries-excluded", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"USA", "CAN"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder1"}, + "GBR": []string{}, + "*": []string{}, + }, + }, + { + name: "no-countries-excluded", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "GBR": []string{}, + "*": []string{}, + }, + }, + { + name: "existing-excluded-bidders-preserved", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{"existing-bidder"}, + "CAN": []string{"existing-bidder"}, + "GBR": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{"existing-bidder", "bidder1"}, + "CAN": []string{"existing-bidder"}, + "GBR": []string{}, + }, + }, + { + name: "empty-country-exclusions", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"USA"}, + }, + countryExclusions: CountryExclusions{}, + expected: CountryExclusions{}, + }, + { + name: "specifically-excluded-wildcard", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"*"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "*": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + "*": []string{"bidder1"}, + }, + }, + { + name: "country-not-in-exclusions-map", + config: parsedConfig{ + bidder: "bidder1", + singleCountriesExcluded: []string{"BRA"}, + }, + countryExclusions: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + }, + expected: CountryExclusions{ + "USA": []string{}, + "CAN": []string{}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder := &bidderConfigRuleSetBuilder[RequestWrapper, ProcessedAuctionHookResult]{} + + builder.markBlockListExclusions(tc.config, tc.countryExclusions) + + // Check that all expected keys exist with the right values + for country, expectedBidders := range tc.expected { + assert.ElementsMatch(t, expectedBidders, tc.countryExclusions[country], + "Country %s should have the expected excluded bidders", country) + } + + // Check that there are no unexpected keys + assert.Equal(t, len(tc.expected), len(tc.countryExclusions), + "Expected and actual CountryExclusions should have the same number of entries") + }) + } +} + +func TestAddTreeNodes(t *testing.T) { + testCases := []struct { + name string + countryExclusions CountryExclusions + expectedChildren int + }{ + { + name: "nil-exclusions", + countryExclusions: CountryExclusions{}, + expectedChildren: 0, + }, + { + name: "empty-exclusions", + countryExclusions: CountryExclusions{}, + expectedChildren: 0, + }, + { + name: "single-country-exclusion", + countryExclusions: CountryExclusions{ + "USA": []string{"bidder1"}, + }, + expectedChildren: 1, + }, + { + name: "multiple-country-exclusions", + countryExclusions: CountryExclusions{ + "USA": []string{"bidder1"}, + "CAN": []string{"bidder2"}, + "MEX": []string{"bidder3"}, + }, + expectedChildren: 3, + }, + { + name: "country-with-multiple-bidders", + countryExclusions: CountryExclusions{ + "USA": []string{"bidder1", "bidder2", "bidder3"}, + }, + expectedChildren: 1, + }, + { + name: "mixed-exclusions", + countryExclusions: CountryExclusions{ + "USA": []string{"bidder1", "bidder2"}, + "CAN": []string{"bidder3"}, + "*": []string{"bidder4"}, + }, + expectedChildren: 3, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + root := &rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + Children: make(map[string]*rules.Node[RequestWrapper, ProcessedAuctionHookResult]), + } + addTreeNodes(root, tc.countryExclusions) + + assert.Len(t, root.Children, tc.expectedChildren) + + // Check that each country has a node with the correct bidders + for country, excludedBidders := range tc.countryExclusions { + childNode, exists := root.Children[country] + assert.True(t, exists, "Expected child node for country %s", country) + + if exists { + assert.Len(t, childNode.ResultFunctions, 1) + + if len(childNode.ResultFunctions) > 0 { + assert.IsType(t, &ExcludeBidders{}, childNode.ResultFunctions[0]) + + // Check that the result function is of type ExcludeBidders + excludeBidders, ok := childNode.ResultFunctions[0].(*ExcludeBidders) + assert.True(t, ok, "Expected result function to be of type ExcludeBidders") + + if ok { + // Check that the bidders in the config match what we expect + assert.ElementsMatch(t, excludedBidders, excludeBidders.Args.Bidders, + "Country %s: Expected bidders %v, got %v", country, excludedBidders, excludeBidders.Args.Bidders) + } + } + } + } + }) + } +} diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_test.go b/modules/prebid/rulesengine/bidder_config_ruleset_test.go new file mode 100644 index 0000000000..93af63cd21 --- /dev/null +++ b/modules/prebid/rulesengine/bidder_config_ruleset_test.go @@ -0,0 +1,203 @@ +package rulesengine + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v3/rules" + "github.com/stretchr/testify/assert" +) + +func TestBuildBidderConfigRuleSet(t *testing.T) { + deviceCountry, _ := rules.NewDeviceCountry(json.RawMessage{}) + + testCases := []struct { + name string + geoscopes map[string][]string + expectError bool + expectedRuleSet cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult] + }{ + { + name: "nil-geoscopes", + geoscopes: nil, + expectError: false, + expectedRuleSet: cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult]{ + name: "Dynamic ruleset from geoscopes", + modelGroups: []cacheModelGroup[RequestWrapper, ProcessedAuctionHookResult]{ + { + weight: 100, + version: "1.0", + analyticsKey: "bidderConfig", + tree: rules.Tree[RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + SchemaFunction: nil, + Children: nil, + }, + }, + }, + }, + }, + }, + { + name: "empty-geoscopes", + geoscopes: map[string][]string{}, + expectError: false, + expectedRuleSet: cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult]{ + name: "Dynamic ruleset from geoscopes", + modelGroups: []cacheModelGroup[RequestWrapper, ProcessedAuctionHookResult]{ + { + weight: 100, + version: "1.0", + analyticsKey: "bidderConfig", + tree: rules.Tree[RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + SchemaFunction: nil, + Children: nil, + }, + }, + }, + }, + }, + }, + { + name: "valid-geoscopes", + geoscopes: map[string][]string{ + "bidder1": {"USA", "CAN"}, + "bidder2": {"GBR", "FRA"}, + }, + expectError: false, + expectedRuleSet: cacheRuleSet[RequestWrapper, ProcessedAuctionHookResult]{ + name: "Dynamic ruleset from geoscopes", + modelGroups: []cacheModelGroup[RequestWrapper, ProcessedAuctionHookResult]{ + { + weight: 100, + version: "1.0", + analyticsKey: "bidderConfig", + tree: rules.Tree[RequestWrapper, ProcessedAuctionHookResult]{ + Root: &rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + SchemaFunction: deviceCountry, + Children: map[string]*rules.Node[RequestWrapper, ProcessedAuctionHookResult]{ + "USA": { + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: []string{"bidder2"}, + }, + }, + }, + Children: nil, + }, + "CAN": { + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: []string{"bidder2"}, + }, + }, + }, + Children: nil, + }, + "GBR": { + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: []string{"bidder1"}, + }, + }, + }, + Children: nil, + }, + "FRA": { + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: []string{"bidder1"}, + }, + }, + }, + Children: nil, + }, + "*": { + ResultFunctions: []rules.ResultFunction[RequestWrapper, ProcessedAuctionHookResult]{ + &ExcludeBidders{ + Args: config.ResultFuncParams{ + Bidders: []string{"bidder1", "bidder2"}, + }, + }, + }, + Children: nil, + }, + }, + }, + }, + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ruleSets, err := buildBidderConfigRuleSet(tc.geoscopes, nil) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + + assert.Len(t, ruleSets, 1) + + // Check basic structure properties instead of full equality + assert.Equal(t, tc.expectedRuleSet.name, ruleSets[0].name) + assert.Len(t, ruleSets[0].modelGroups, len(tc.expectedRuleSet.modelGroups)) + + if len(ruleSets[0].modelGroups) > 0 && len(tc.expectedRuleSet.modelGroups) > 0 { + // Check model group properties + assert.Equal(t, tc.expectedRuleSet.modelGroups[0].weight, ruleSets[0].modelGroups[0].weight) + assert.Equal(t, tc.expectedRuleSet.modelGroups[0].version, ruleSets[0].modelGroups[0].version) + assert.Equal(t, tc.expectedRuleSet.modelGroups[0].analyticsKey, ruleSets[0].modelGroups[0].analyticsKey) + + // For non-empty geoscopes, verify tree structure + if tc.name == "valid-geoscopes" { + root := ruleSets[0].modelGroups[0].tree.Root + assert.NotNil(t, root) + assert.NotNil(t, root.SchemaFunction) + assert.NotNil(t, root.Children) + + // Check expected country nodes exist + assert.Contains(t, root.Children, "USA") + assert.Contains(t, root.Children, "CAN") + assert.Contains(t, root.Children, "GBR") + assert.Contains(t, root.Children, "FRA") + assert.Contains(t, root.Children, "*") + + // Check USA node has expected result function for bidder2 + usaNode := root.Children["USA"] + assert.Len(t, usaNode.ResultFunctions, 1) + + // Check CAN node has expected result function for bidder2 + canNode := root.Children["CAN"] + assert.Len(t, canNode.ResultFunctions, 1) + + // Check GBR node has expected result function for bidder1 + gbrNode := root.Children["GBR"] + assert.Len(t, gbrNode.ResultFunctions, 1) + + // Check FRA node has expected result function for bidder1 + fraNode := root.Children["FRA"] + assert.Len(t, fraNode.ResultFunctions, 1) + + // Check * node has expected result function for both bidders + wildcardNode := root.Children["*"] + assert.Len(t, wildcardNode.ResultFunctions, 1) + } else { + // For empty or nil geoscopes, verify root exists but might be empty + root := ruleSets[0].modelGroups[0].tree.Root + assert.NotNil(t, root) + } + } + }) + } +} diff --git a/modules/prebid/rulesengine/cache_entry.go b/modules/prebid/rulesengine/cache_entry.go index 8774023c99..5b995dd6e7 100644 --- a/modules/prebid/rulesengine/cache_entry.go +++ b/modules/prebid/rulesengine/cache_entry.go @@ -35,7 +35,7 @@ type cacheModelGroup[T1 any, T2 any] struct { // NewCacheEntry creates a new cache object for the given configuration // It builds the tree structures for the rule sets for the processed auction request stage // and stores them in the cache object -func NewCacheEntry(cfg *config.PbRulesEngine, cfgRaw *json.RawMessage) (cacheEntry, error) { +func NewCacheEntry(cfg *config.PbRulesEngine, cfgRaw *json.RawMessage, geoscopes map[string][]string) (cacheEntry, error) { if cfg == nil { return cacheEntry{}, errors.New("no rules engine configuration provided") } @@ -51,6 +51,14 @@ func NewCacheEntry(cfg *config.PbRulesEngine, cfgRaw *json.RawMessage) (cacheEnt hashedConfig: idHash, } + if cfg.GenerateRulesFromBidderConfig { + bidderConfigRuleSet, err := buildBidderConfigRuleSet(geoscopes, cfg.SetDefinitions.CountryGroups) + if err != nil { + return cacheEntry{}, err + } + newCacheObj.ruleSetsForProcessedAuctionRequestStage = bidderConfigRuleSet + } + for _, ruleSet := range cfg.RuleSets { if ruleSet.Stage != hooks.StageProcessedAuctionRequest { // TODO: log error / metric --> stage not supported diff --git a/modules/prebid/rulesengine/cache_entry_test.go b/modules/prebid/rulesengine/cache_entry_test.go index c06629de09..481f1a26c0 100644 --- a/modules/prebid/rulesengine/cache_entry_test.go +++ b/modules/prebid/rulesengine/cache_entry_test.go @@ -14,48 +14,48 @@ import ( func TestNewCacheEntry(t *testing.T) { testCases := []struct { - name string - inCfg *config.PbRulesEngine - inCfgRaw *json.RawMessage - expectEmptyRulesetArray bool - expectedErr error + name string + inCfg *config.PbRulesEngine + inCfgRaw *json.RawMessage + expectedRulesetCount int + expectedErr error }{ { - name: "nil-ruleset-config", - expectEmptyRulesetArray: true, - expectedErr: errors.New("no rules engine configuration provided"), + name: "nil-ruleset-config", + expectedRulesetCount: 0, + expectedErr: errors.New("no rules engine configuration provided"), }, { - name: "nil-cfgRaw", - inCfg: &config.PbRulesEngine{}, - expectEmptyRulesetArray: true, - expectedErr: errors.New("Can't create identifier hash from empty raw json configuration"), + name: "nil-cfgRaw", + inCfg: &config.PbRulesEngine{}, + expectedRulesetCount: 0, + expectedErr: errors.New("Can't create identifier hash from empty raw json configuration"), }, { - name: "nil-ruleset-array", - inCfg: &config.PbRulesEngine{}, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: true, - expectedErr: nil, + name: "nil-ruleset-array", + inCfg: &config.PbRulesEngine{}, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 0, + expectedErr: nil, }, { name: "empty-ruleset-array", inCfg: &config.PbRulesEngine{ RuleSets: []config.RuleSet{}, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: true, - expectedErr: nil, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 0, + expectedErr: nil, }, { - name: "ruleset-with-wrong-stage", + name: "static-ruleset-with-wrong-stage", inCfg: &config.PbRulesEngine{ RuleSets: []config.RuleSet{ {Stage: "wrong-stage"}, }, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: true, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 0, }, { name: "createCacheRuleSet-throws-error", @@ -75,12 +75,44 @@ func TestNewCacheEntry(t *testing.T) { }, }, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: true, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 0, }, { - name: "single-ruleset-entry-right-stage", + name: "dynamic-ruleset", inCfg: &config.PbRulesEngine{ + GenerateRulesFromBidderConfig: true, + RuleSets: []config.RuleSet{}, + }, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 1, + }, + { + name: "single-static-ruleset", + inCfg: &config.PbRulesEngine{ + RuleSets: []config.RuleSet{ + { + Stage: hooks.StageProcessedAuctionRequest, + ModelGroups: []config.ModelGroup{ + { + Default: []config.Result{ + { + Func: ExcludeBiddersName, + Args: json.RawMessage(`{"bidders": ["bidderA"], "seatNonBid": 111}`), + }, + }, + }, + }, + }, + }, + }, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 1, + }, + { + name: "single-static-ruleset-with-dynamic-ruleset", + inCfg: &config.PbRulesEngine{ + GenerateRulesFromBidderConfig: true, RuleSets: []config.RuleSet{ { Stage: hooks.StageProcessedAuctionRequest, @@ -97,11 +129,11 @@ func TestNewCacheEntry(t *testing.T) { }, }, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: false, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 2, }, { - name: "Multiple-ruleset-entries-some-with-the-wrong-stage", + name: "multiple-static-rulesets-some-with-the-wrong-stage", inCfg: &config.PbRulesEngine{ RuleSets: []config.RuleSet{ {Stage: "wrong-stage"}, @@ -120,8 +152,8 @@ func TestNewCacheEntry(t *testing.T) { }, }, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: false, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 1, }, { name: "Multiple-entries-with-supported-rulesets", @@ -141,7 +173,7 @@ func TestNewCacheEntry(t *testing.T) { }, }, { - Stage: "processed_auction", + Stage: hooks.StageProcessedAuctionRequest, ModelGroups: []config.ModelGroup{ { Default: []config.Result{ @@ -155,21 +187,16 @@ func TestNewCacheEntry(t *testing.T) { }, }, }, - inCfgRaw: getValidJsonConfig(), - expectEmptyRulesetArray: false, + inCfgRaw: getValidJsonConfig(), + expectedRulesetCount: 2, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - cacheEntry, err := NewCacheEntry(tc.inCfg, tc.inCfgRaw) - - if tc.expectEmptyRulesetArray { - assert.Empty(t, cacheEntry.ruleSetsForProcessedAuctionRequestStage) - } else { - assert.NotEmpty(t, cacheEntry.ruleSetsForProcessedAuctionRequestStage) - } + cacheEntry, err := NewCacheEntry(tc.inCfg, tc.inCfgRaw, map[string][]string{}) + assert.Len(t, cacheEntry.ruleSetsForProcessedAuctionRequestStage, tc.expectedRulesetCount) assert.Equal(t, tc.expectedErr, err) }) } @@ -381,8 +408,13 @@ func getValidJsonConfig() *json.RawMessage { rv := json.RawMessage(` { "enabled": true, - "generateRulesFromBidderConfig": true, + "generate_rules_from_bidderconfig": true, "timestamp": "20250131 00:00:00", + "set_definitions": { + "country_groups": { + "EEA": ["FRA", "DEU"] + } + }, "rulesets": [ { "stage": "processed_auction_request", diff --git a/modules/prebid/rulesengine/config/config.go b/modules/prebid/rulesengine/config/config.go index 7f7978a27b..0dc4bded5d 100644 --- a/modules/prebid/rulesengine/config/config.go +++ b/modules/prebid/rulesengine/config/config.go @@ -16,9 +16,15 @@ const RulesEngineSchemaFile = "rules-engine-schema.json" const RulesEngineSchemaFilePath = "modules/prebid/rulesengine/config/" + RulesEngineSchemaFile type PbRulesEngine struct { - Enabled bool `json:"enabled,omitempty"` - Timestamp string `json:"timestamp,omitempty"` - RuleSets []RuleSet `json:"rulesets,omitempty"` + Enabled bool `json:"enabled,omitempty"` + GenerateRulesFromBidderConfig bool `json:"generate_rules_from_bidderconfig,omitempty"` + SetDefinitions SetDefinitions `json:"set_definitions,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + RuleSets []RuleSet `json:"rulesets,omitempty"` +} + +type SetDefinitions struct { + CountryGroups map[string][]string `json:"country_groups,omitempty"` } type RuleSet struct { diff --git a/modules/prebid/rulesengine/config/config_test.go b/modules/prebid/rulesengine/config/config_test.go index 7dce487627..1c119d3bf0 100644 --- a/modules/prebid/rulesengine/config/config_test.go +++ b/modules/prebid/rulesengine/config/config_test.go @@ -93,275 +93,330 @@ func TestValidateConfig(t *testing.T) { validator, err := CreateSchemaValidator(RulesEngineSchemaFile) assert.NoError(t, err, fmt.Sprintf("could not create schema validator using file %s", RulesEngineSchemaFile)) - type testInput struct { - inConfig json.RawMessage - outErrMsg string - } - - testGroups := []struct { - desc string - tests []testInput + tests := []struct { + name string + config json.RawMessage + expectedError string }{ { - "nil rules engine config", - []testInput{{nil, "EOF"}}, + name: "nil-config", + config: nil, + expectedError: "EOF", }, { - "malformed rules engine config", - []testInput{{json.RawMessage(`malformed`), "invalid character 'm' looking for beginning of value"}}, + name: "invalid-malformed-config", + config: json.RawMessage(`malformed`), + expectedError: "invalid character 'm' looking for beginning of value", }, { - "Well formed config fails schema validation", - []testInput{ - { //0 - json.RawMessage(`{}`), - "[(root): enabled is required] [(root): rulesets is required] ", - }, - { //1 - json.RawMessage(`{"enabled": true}`), - "[(root): rulesets is required] ", - }, - { //2 - json.RawMessage(`{"enabled": true, "rulesets": []}`), - "[rulesets: Array must have at least 1 items] ", - }, - { //3 - json.RawMessage(`{"enabled": true, "rulesets": [{}]}`), - "[rulesets.0: stage is required] [rulesets.0: name is required] [rulesets.0: modelgroups is required] ", - }, - { //4 - json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"a"}]}`), - "[rulesets.0: name is required] [rulesets.0: modelgroups is required] [rulesets.0.stage: rulesets.0.stage must be one of the following: \"entrypoint\", \"raw_auction_request\", \"processed_auction_request\", \"bidder_request\", \"raw_bidder_response\", \"all_processed_bid_responses\", \"auction_response\"] ", - }, - { //5 - json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint"}]}`), - "[rulesets.0: name is required] [rulesets.0: modelgroups is required] ", - }, - { //6 - json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint","name":"n"}]}`), - "[rulesets.0: modelgroups is required] ", - }, - { //7 - json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint","name":"n","modelgroups":[]}]}`), - "[rulesets.0.modelgroups: Array must have at least 1 items] ", - }, - { //8 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "n", - "modelgroups": [ - { - "weight": 101, - "schema": [{"function":"channel"}], - "rules": [ - { - "conditions": ["cond"], - "results": [{"function": "excludeBidders"}] - } - ] - } - ] - } - ] - } - `), - "[rulesets.0.modelgroups.0.weight: Must be less than or equal to 100] ", - }, - { //9 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "n", - "modelgroups": [ - { - "weight": -1, - "schema": [{"function":"channel"}], - "rules": [ - { - "conditions": ["cond"], - "results": [{"function": "excludeBidders"}] - } - ] - } - ] - } - ] - } - `), - "[rulesets.0.modelgroups.0.weight: Must be greater than or equal to 1] ", - }, - { //10 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "n", - "modelgroups": [ - { - "schema": [], - "rules": [ - { - "conditions": ["cond"], - "results": [{"function": "excludeBidders"}] - } - ] - } - ] - } - ] - } - `), - "", - }, - { //11 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "n", - "modelgroups": [ - { - "schema": [{"function":"channel"}], - "rules": [] - } - ] - } - ] - } - `), - "", - }, - { //12 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "someName", - "modelgroups": [ - { - "schema": [{"function":"foo"}], - "rules": [ - { - "conditions": ["cond"], - "results": [{"function": "excludeBidders"}] - } - ] - } - ] - } - ] - } - `), - "[rulesets.0.modelgroups.0.schema.0.function: rulesets.0.modelgroups.0.schema.0.function must be one of the following: \"channel\", \"dataCenter\", \"dataCenterIn\", \"deviceCountry\", \"deviceCountryIn\", \"eidAvailable\", \"eidIn\", \"fpdAvailable\", \"gppSidAvailable\", \"gppSidIn\", \"percent\", \"tcfInScope\", \"userFpdAvailable\"] ", - }, - { //13 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "someName", - "modelgroups": [ - { - "schema": [{"function":"channel"}], - "rules": [ - { - "conditions": [], - "results": [{"function": "excludeBidders"}] - } - ] - } - ] - } - ] - } - `), - "[rulesets.0.modelgroups.0.rules.0.conditions: Array must have at least 1 items] ", - }, - { //14 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "someName", - "modelgroups": [ - { - "schema": [{"function":"channel"}], - "rules": [ - { - "conditions": ["cond"], - "results": [] - } - ] - } - ] - } - ] - } - `), - "", + name: "invalid-missing-enabled-and-rulesets", + config: json.RawMessage(`{}`), + expectedError: "[(root): enabled is required] [(root): rulesets is required] ", + }, + { + name: "invalid-missing-rulesets", + config: json.RawMessage(`{"enabled": true}`), + expectedError: "[(root): rulesets is required] ", + }, + { + name: "invalid-missing-ruleset-name-and-modelgroups", + config: json.RawMessage(`{"enabled": true, "rulesets": [{}]}`), + expectedError: "[rulesets.0: stage is required] [rulesets.0: name is required] [rulesets.0: modelgroups is required] ", + }, + { + name: "invalid-missing-ruleset-modelgroups-and-valid-stage-name", + config: json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"a"}]}`), + expectedError: "[rulesets.0: name is required] [rulesets.0: modelgroups is required] [rulesets.0.stage: rulesets.0.stage must be one of the following: \"entrypoint\", \"raw_auction_request\", \"processed_auction_request\", \"bidder_request\", \"raw_bidder_response\", \"all_processed_bid_responses\", \"auction_response\"] ", + }, + { + name: "invalid-missing-ruleset-name-and-modelgroups", + config: json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint"}]}`), + expectedError: "[rulesets.0: name is required] [rulesets.0: modelgroups is required] ", + }, + { + name: "invalid-missing-modelgroups", + config: json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint","name":"n"}]}`), + expectedError: "[rulesets.0: modelgroups is required] ", + }, + { + name: "invalid-empty-modelgroups", + config: json.RawMessage(`{"enabled": true, "rulesets": [{"stage":"entrypoint","name":"n","modelgroups":[]}]}`), + expectedError: "[rulesets.0.modelgroups: Array must have at least 1 items] ", + }, + { + name: "invalid-weight-high", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "weight": 101, + "schema": [{"function":"channel"}], + "rules": [ + { + "conditions": ["cond"], + "results": [{"function": "excludeBidders"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "[rulesets.0.modelgroups.0.weight: Must be less than or equal to 100] ", + }, + { + name: "invalid-weight-low", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "weight": -1, + "schema": [{"function":"channel"}], + "rules": [ + { + "conditions": ["cond"], + "results": [{"function": "excludeBidders"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "[rulesets.0.modelgroups.0.weight: Must be greater than or equal to 1] ", + }, + { + name: "invalid-missing-schema-function", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "schema": [], + "rules": [ + { + "conditions": ["cond"], + "results": [{"function": "excludeBidders"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "", + }, + { + name: "valid-empty-rules", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [] + } + ] + } + ] + } + `), + expectedError: "", + }, + { + name: "invalid-schema-function", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "someName", + "modelgroups": [ + { + "schema": [{"function":"foo"}], + "rules": [ + { + "conditions": ["cond"], + "results": [{"function": "excludeBidders"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "[rulesets.0.modelgroups.0.schema.0.function: rulesets.0.modelgroups.0.schema.0.function must be one of the following: \"channel\", \"dataCenter\", \"dataCenterIn\", \"deviceCountry\", \"deviceCountryIn\", \"eidAvailable\", \"eidIn\", \"fpdAvailable\", \"gppSidAvailable\", \"gppSidIn\", \"percent\", \"tcfInScope\", \"userFpdAvailable\"] ", + }, + { + name: "invalid-empty-conditions", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "someName", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [ + { + "conditions": [], + "results": [{"function": "excludeBidders"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "[rulesets.0.modelgroups.0.rules.0.conditions: Array must have at least 1 items] ", + }, + { + name: "valid-empty-results", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "someName", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [ + { + "conditions": ["cond"], + "results": [] + } + ] + } + ] + } + ] + } + `), + expectedError: "", + }, + { + name: "invalid-result-function", + config: json.RawMessage(` + { + "enabled": true, + "rulesets": [ + { + "stage": "entrypoint", + "name": "someName", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [ + { + "conditions": ["cond"], + "results": [{"function": "foobar"}] + } + ] + } + ] + } + ] + } + `), + expectedError: "[rulesets.0.modelgroups.0.rules.0.results.0.function: rulesets.0.modelgroups.0.rules.0.results.0.function must be one of the following: \"excludeBidders\", \"includeBidders\", \"logATag\"] ", + }, + { + name: "invalid-set-definitions-invalid-property", + config: json.RawMessage(` + { + "enabled": true, + "set_definitions": { + "invalid": { + "EEA": ["FRA"] + } }, - { //15 - json.RawMessage(` - { - "enabled": true, - "rulesets": [ - { - "stage": "entrypoint", - "name": "someName", - "modelgroups": [ - { - "schema": [{"function":"channel"}], - "rules": [ - { - "conditions": ["cond"], - "results": [{"function": "foobar"}] - } - ] - } - ] - } - ] - } - `), - "[rulesets.0.modelgroups.0.rules.0.results.0.function: rulesets.0.modelgroups.0.rules.0.results.0.function must be one of the following: \"excludeBidders\", \"includeBidders\", \"logATag\"] ", + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [] + } + ] + } + ] + } + `), + expectedError: "[set_definitions: Additional property invalid is not allowed] ", + }, + { + name: "invalid-set-definitions-valid-property-invalid-value", + config: json.RawMessage(` + { + "enabled": true, + "set_definitions": { + "country_groups": { + "EEA": [123] + } }, - }, + "rulesets": [ + { + "stage": "entrypoint", + "name": "n", + "modelgroups": [ + { + "schema": [{"function":"channel"}], + "rules": [] + } + ] + } + ] + } + `), + expectedError: "[set_definitions.country_groups.EEA.0: Invalid type. Expected: string, given: integer] ", }, { - "successful rules engine schema validation", - []testInput{{getValidJsonConfig(), ""}}, + name: "valid-config", + config: getValidJsonConfig(), + expectedError: "", }, } - for _, tg := range testGroups { - for i, tc := range tg.tests { - t.Run(fmt.Sprintf("%s test %d", tg.desc, i), func(t *testing.T) { - actualError := validateConfig(tc.inConfig, validator) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actualError := validateConfig(test.config, validator) - if len(tc.outErrMsg) > 0 { - assert.EqualError(t, actualError, tc.outErrMsg) - } else { - assert.NoError(t, actualError) - } - }) - } + if len(test.expectedError) > 0 { + assert.EqualError(t, actualError, test.expectedError) + } else { + assert.NoError(t, actualError) + } + }) } } @@ -475,7 +530,12 @@ func getValidJsonConfig() json.RawMessage { return json.RawMessage(` { "enabled": true, - "generateRulesFromBidderConfig": true, + "generate_rules_from_bidderconfig": true, + "set_definitions": { + "country_groups": { + "CUSTOM_GROUP": ["USA", "CAN"] + } + }, "timestamp": "20250131 00:00:00", "rulesets": [ { @@ -616,7 +676,13 @@ func getInvalidRuleSetConfig() json.RawMessage { func getValidConfig() *PbRulesEngine { return &PbRulesEngine{ - Enabled: true, + Enabled: true, + GenerateRulesFromBidderConfig: true, + SetDefinitions: SetDefinitions{ + CountryGroups: map[string][]string{ + "CUSTOM_GROUP": {"USA", "CAN"}, + }, + }, Timestamp: "20250131 00:00:00", RuleSets: []RuleSet{ { diff --git a/modules/prebid/rulesengine/config/rules-engine-schema.json b/modules/prebid/rulesengine/config/rules-engine-schema.json index ca9a81ae61..87b1872248 100644 --- a/modules/prebid/rulesengine/config/rules-engine-schema.json +++ b/modules/prebid/rulesengine/config/rules-engine-schema.json @@ -8,13 +8,31 @@ "type": "boolean", "description": "pending" }, + "generate_rules_from_bidderconfig": { + "type": "boolean", + "description": "If true, rules will be generated from the bidder config. If false, all rules must be defined in the rulesets." + }, + "set_definitions": { + "type": "object", + "properties": { + "country_groups": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, "timestamp": { "type": "string", "description": "pending" }, "rulesets": { "type": "array", - "minItems": 1, "items": { "type": "object", "properties": { diff --git a/modules/prebid/rulesengine/module.go b/modules/prebid/rulesengine/module.go index bfea26d92f..ca63c763b9 100644 --- a/modules/prebid/rulesengine/module.go +++ b/modules/prebid/rulesengine/module.go @@ -16,7 +16,7 @@ import ( // Builder configures the rules engine module initiating an in-memory cache and kicking // off a go routine that builds tree structures that represent rule sets optimized for finding // a rule to applies for a given request. -func Builder(cfg json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { +func Builder(cfg json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, error) { schemaValidator, err := config.CreateSchemaValidator(config.RulesEngineSchemaFilePath) if err != nil { return nil, err @@ -25,6 +25,7 @@ func Builder(cfg json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) tm := treeManager{ done: make(chan struct{}), requests: make(chan buildInstruction), + geoscopes: deps.Geoscope, schemaValidator: schemaValidator, monitor: &treeManagerLogger{}, } @@ -95,9 +96,7 @@ func (m Module) HandleProcessedAuctionHook( }, nil } - ruleSets := co.ruleSetsForProcessedAuctionRequestStage - - return handleProcessedAuctionHook(ruleSets, payload) + return handleProcessedAuctionHook(co.ruleSetsForProcessedAuctionRequestStage, payload) } // Shutdown signals the module to stop processing and waits for the tree manager to finish diff --git a/modules/prebid/rulesengine/module_test.go b/modules/prebid/rulesengine/module_test.go index 687d75a076..2cf2bd59bb 100644 --- a/modules/prebid/rulesengine/module_test.go +++ b/modules/prebid/rulesengine/module_test.go @@ -2,12 +2,109 @@ package rulesengine import ( "encoding/json" + "os" + "path/filepath" "testing" "time" + "github.com/prebid/prebid-server/v3/modules/moduledeps" "github.com/stretchr/testify/assert" ) +// TestBuilderWithWorkingDir tests the Builder function by changing the working directory +// to ensure the schema file can be found +func TestBuilderWithWorkingDir(t *testing.T) { + // Save the current working directory + origWd, err := os.Getwd() + if err != nil { + t.Fatalf("Failed to get current working directory: %v", err) + } + + // Change to the project root directory + err = os.Chdir(filepath.Join(origWd, "..", "..", "..")) + if err != nil { + t.Fatalf("Failed to change to project root directory: %v", err) + } + + // Restore the original working directory when the test is done + defer func() { + err := os.Chdir(origWd) + if err != nil { + t.Fatalf("Failed to restore original working directory: %v", err) + } + }() + + testCases := []struct { + name string + config json.RawMessage + deps moduledeps.ModuleDeps + expectError bool + expectedModuleOK bool + }{ + { + name: "empty-config", + config: json.RawMessage(``), + deps: moduledeps.ModuleDeps{}, + expectError: false, + expectedModuleOK: true, + }, + { + name: "nil-config", + config: nil, + deps: moduledeps.ModuleDeps{}, + expectError: false, + expectedModuleOK: true, + }, + { + name: "invalid-config", + config: json.RawMessage(`{"enabled": true, "refreshrateseconds": "invalid-format"}`), + deps: moduledeps.ModuleDeps{}, + expectError: true, + expectedModuleOK: false, + }, + { + name: "with-geoscope-data", + config: json.RawMessage(``), + deps: moduledeps.ModuleDeps{ + Geoscope: map[string][]string{ + "bidder1": {"USA", "CAN"}, + "bidder2": {"GBR", "FRA"}, + }, + }, + expectError: false, + expectedModuleOK: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Call the Builder function directly + module, err := Builder(tc.config, tc.deps) + + // Check for expected errors + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + + // For non-error cases, verify the module structure + if !tc.expectError && tc.expectedModuleOK { + // Verify the module is not nil + assert.NotNil(t, module) + + // Type assertion to Module + m, ok := module.(Module) + assert.True(t, ok, "Expected module to be of type Module") + + // Verify module components are initialized + assert.NotNil(t, m.Cache) + assert.NotNil(t, m.TreeManager) + } + }) + } +} + var sampleJsonConfig json.RawMessage = json.RawMessage(`{"enabled": true, "ruleSets": []}`) func TestConfigChanged(t *testing.T) { diff --git a/modules/prebid/rulesengine/tree_manager.go b/modules/prebid/rulesengine/tree_manager.go index 6e72853f88..35496e7591 100644 --- a/modules/prebid/rulesengine/tree_manager.go +++ b/modules/prebid/rulesengine/tree_manager.go @@ -18,6 +18,7 @@ type buildInstruction struct { type treeManager struct { done chan struct{} requests chan buildInstruction + geoscopes map[string][]string schemaValidator *gojsonschema.Schema monitor RulesEngineObserver } @@ -48,7 +49,7 @@ func (tm *treeManager) Run(c cacher) error { break } - newCacheObj, err := NewCacheEntry(parsedCfg, req.config) + newCacheObj, err := NewCacheEntry(parsedCfg, req.config, tm.geoscopes) if err != nil { tm.monitor.logError(fmt.Sprintf("Rules engine error creating cache entry for account %s: %v", req.accountID, err)) break diff --git a/modules/prebid/rulesengine/tree_manager_test.go b/modules/prebid/rulesengine/tree_manager_test.go index 818b21c6dd..b397074860 100644 --- a/modules/prebid/rulesengine/tree_manager_test.go +++ b/modules/prebid/rulesengine/tree_manager_test.go @@ -248,7 +248,7 @@ func getDisabledJsonConfig() *json.RawMessage { rv := json.RawMessage(` { "enabled": false, - "generateRulesFromBidderConfig": true, + "generate_rules_from_bidderconfig": true, "timestamp": "20250131 00:00:00", "rulesets": [ { @@ -340,7 +340,7 @@ func getJsonConfigUnknownFunction() *json.RawMessage { rv := json.RawMessage(` { "enabled": true, - "generateRulesFromBidderConfig": true, + "generate_rules_from_bidderconfig": true, "timestamp": "20250131 00:00:00", "rulesets": [ { diff --git a/router/router.go b/router/router.go index 3f5970b965..c7db28ad96 100644 --- a/router/router.go +++ b/router/router.go @@ -208,7 +208,8 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R syncerKeys = append(syncerKeys, k) } - moduleDeps := moduledeps.ModuleDeps{HTTPClient: generalHttpClient, RateConvertor: rateConvertor} + normalizedGeoscopes := getNormalizedGeoscopes(cfg.BidderInfos) + moduleDeps := moduledeps.ModuleDeps{HTTPClient: generalHttpClient, RateConvertor: rateConvertor, Geoscope: normalizedGeoscopes} repo, moduleStageNames, shutdownModules, err := modules.NewBuilder().Build(cfg.Hooks.Modules, moduleDeps) if err != nil { glog.Fatalf("Failed to init hook modules: %v", err) @@ -408,3 +409,18 @@ func readDefaultRequestFromFile(defReqConfig config.DefReqConfig) []byte { return defaultRequestJSON } + +func getNormalizedGeoscopes(bidderInfos config.BidderInfos) map[string][]string { + geoscopes := make(map[string][]string, len(bidderInfos)) + + for name, info := range bidderInfos { + if len(info.Geoscope) > 0 { + uppercasedGeoscopes := make([]string, len(info.Geoscope)) + for i, scope := range info.Geoscope { + uppercasedGeoscopes[i] = strings.ToUpper(scope) + } + geoscopes[name] = uppercasedGeoscopes + } + } + return geoscopes +} diff --git a/router/router_test.go b/router/router_test.go index 08d7468446..2566744609 100644 --- a/router/router_test.go +++ b/router/router_test.go @@ -228,3 +228,92 @@ func TestBidderParamsCompactedOutput(t *testing.T) { // Assertions assert.Equal(t, expectedFormattedResponse, recorder.Body.String()) } + +func TestGetNormalizedGeoscopes(t *testing.T) { + testCases := []struct { + name string + bidderInfos config.BidderInfos + expectedGeoscopes map[string][]string + }{ + { + name: "nil-bidder-infos", + bidderInfos: nil, + expectedGeoscopes: map[string][]string{}, + }, + { + name: "empty-bidder-infos", + bidderInfos: config.BidderInfos{}, + expectedGeoscopes: map[string][]string{}, + }, + { + name: "bidder-with-no-geoscope", + bidderInfos: config.BidderInfos{ + "bidder1": { + Disabled: false, + }, + }, + expectedGeoscopes: map[string][]string{}, + }, + { + name: "bidder-with-empty-geoscope", + bidderInfos: config.BidderInfos{ + "bidder1": { + Disabled: false, + Geoscope: []string{}, + }, + }, + expectedGeoscopes: map[string][]string{}, + }, + { + name: "bidder-with-geoscope", + bidderInfos: config.BidderInfos{ + "bidder1": { + Disabled: false, + Geoscope: []string{"usa", "can"}, + }, + }, + expectedGeoscopes: map[string][]string{ + "bidder1": {"USA", "CAN"}, + }, + }, + { + name: "multiple-bidders-with-geoscope", + bidderInfos: config.BidderInfos{ + "bidder1": { + Disabled: false, + Geoscope: []string{"usa", "can"}, + }, + "bidder2": { + Disabled: false, + Geoscope: []string{"eu", "asia"}, + }, + "bidder3": { + Disabled: false, + }, + }, + expectedGeoscopes: map[string][]string{ + "bidder1": {"USA", "CAN"}, + "bidder2": {"EU", "ASIA"}, + }, + }, + { + name: "mixed-case-geoscope-values", + bidderInfos: config.BidderInfos{ + "bidder1": { + Disabled: false, + Geoscope: []string{"UsA", "Can", "eu"}, + }, + }, + expectedGeoscopes: map[string][]string{ + "bidder1": {"USA", "CAN", "EU"}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualGeoscopes := getNormalizedGeoscopes(tc.bidderInfos) + assert.Equal(t, tc.expectedGeoscopes, actualGeoscopes) + }) + } +} From 1400a64527390ffc0dffece4338ae6a09e233667 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:13:34 -0700 Subject: [PATCH 116/272] In order to protect users of prebid-server that don't use CGO, add build flag (#4058) * In order to protect users of prebid-server that don't use CGO, add build flag. * Conditionally configure fiftyonedegrees. * Because the module file is auto-generated, let it include fiftyonedegrees but just explain that it can't be enabled. * include used packages. * fix builder. * Remove unused file. * Add a test for the Builder when CGO is not enabled. --- .../devicedetection/account_info_extractor.go | 2 ++ .../account_info_extractor_test.go | 2 ++ .../devicedetection/account_validator.go | 2 ++ .../devicedetection/account_validator_test.go | 2 ++ .../fiftyonedegrees/devicedetection/config.go | 2 ++ .../devicedetection/config_test.go | 2 ++ .../fiftyonedegrees/devicedetection/context.go | 2 ++ .../devicedetection/device_detector.go | 2 ++ .../devicedetection/device_detector_test.go | 2 ++ .../devicedetection/device_info_extractor.go | 2 ++ .../device_info_extractor_test.go | 2 ++ .../devicedetection/evidence_extractor.go | 2 ++ .../devicedetection/evidence_extractor_test.go | 2 ++ .../devicedetection/fiftyone_device_types.go | 2 ++ .../fiftyone_device_types_test.go | 2 ++ .../devicedetection/hook_auction_entrypoint.go | 2 ++ .../devicedetection/hook_raw_auction_request.go | 2 ++ .../fiftyonedegrees/devicedetection/models.go | 2 ++ .../devicedetection/models_test.go | 2 ++ .../fiftyonedegrees/devicedetection/module.go | 2 ++ .../devicedetection/module_no_cgo_test.go | 15 +++++++++++++++ .../devicedetection/module_test.go | 2 ++ .../fiftyonedegrees/devicedetection/no-cgo.go | 16 ++++++++++++++++ .../devicedetection/request_headers_extractor.go | 2 ++ .../request_headers_extractor_test.go | 2 ++ .../devicedetection/sua_payload_extractor.go | 2 ++ 26 files changed, 79 insertions(+) create mode 100644 modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go create mode 100644 modules/fiftyonedegrees/devicedetection/no-cgo.go diff --git a/modules/fiftyonedegrees/devicedetection/account_info_extractor.go b/modules/fiftyonedegrees/devicedetection/account_info_extractor.go index 2a5168cfe0..3961ec1137 100644 --- a/modules/fiftyonedegrees/devicedetection/account_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/account_info_extractor.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/account_info_extractor_test.go b/modules/fiftyonedegrees/devicedetection/account_info_extractor_test.go index 2d32f7915b..76cb543c01 100644 --- a/modules/fiftyonedegrees/devicedetection/account_info_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/account_info_extractor_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/account_validator.go b/modules/fiftyonedegrees/devicedetection/account_validator.go index fdff92531a..169850e551 100644 --- a/modules/fiftyonedegrees/devicedetection/account_validator.go +++ b/modules/fiftyonedegrees/devicedetection/account_validator.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import "slices" diff --git a/modules/fiftyonedegrees/devicedetection/account_validator_test.go b/modules/fiftyonedegrees/devicedetection/account_validator_test.go index 25f99e3b79..b3c943bf5a 100644 --- a/modules/fiftyonedegrees/devicedetection/account_validator_test.go +++ b/modules/fiftyonedegrees/devicedetection/account_validator_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/config.go b/modules/fiftyonedegrees/devicedetection/config.go index 7a29812d35..3a83030b6d 100644 --- a/modules/fiftyonedegrees/devicedetection/config.go +++ b/modules/fiftyonedegrees/devicedetection/config.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/config_test.go b/modules/fiftyonedegrees/devicedetection/config_test.go index e2478d82b7..9775eb7a10 100644 --- a/modules/fiftyonedegrees/devicedetection/config_test.go +++ b/modules/fiftyonedegrees/devicedetection/config_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/context.go b/modules/fiftyonedegrees/devicedetection/context.go index 3c10dd2f39..b16495ef1f 100644 --- a/modules/fiftyonedegrees/devicedetection/context.go +++ b/modules/fiftyonedegrees/devicedetection/context.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection // Context keys for device detection diff --git a/modules/fiftyonedegrees/devicedetection/device_detector.go b/modules/fiftyonedegrees/devicedetection/device_detector.go index 5c23deb963..9f66c64eea 100644 --- a/modules/fiftyonedegrees/devicedetection/device_detector.go +++ b/modules/fiftyonedegrees/devicedetection/device_detector.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/device_detector_test.go b/modules/fiftyonedegrees/devicedetection/device_detector_test.go index 84d6ab28cc..c113aec7ac 100644 --- a/modules/fiftyonedegrees/devicedetection/device_detector_test.go +++ b/modules/fiftyonedegrees/devicedetection/device_detector_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go index 89ff3714ee..5f70ad5849 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go index 197e392860..23bee8a5d5 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go index 5bec2f4a79..700f53117d 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go index 6b2f9b3ea8..7dc4fb9790 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/fiftyone_device_types.go b/modules/fiftyonedegrees/devicedetection/fiftyone_device_types.go index 1790939e8b..3e104fc74e 100644 --- a/modules/fiftyonedegrees/devicedetection/fiftyone_device_types.go +++ b/modules/fiftyonedegrees/devicedetection/fiftyone_device_types.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/fiftyone_device_types_test.go b/modules/fiftyonedegrees/devicedetection/fiftyone_device_types_test.go index 43b18510e7..84f244f21f 100644 --- a/modules/fiftyonedegrees/devicedetection/fiftyone_device_types_test.go +++ b/modules/fiftyonedegrees/devicedetection/fiftyone_device_types_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go index 7597daa8e0..8be51c422d 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go +++ b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go index 88d0686905..acde532eb5 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go +++ b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/models.go b/modules/fiftyonedegrees/devicedetection/models.go index c58daa211f..ffa9887235 100644 --- a/modules/fiftyonedegrees/devicedetection/models.go +++ b/modules/fiftyonedegrees/devicedetection/models.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection // Prefixes in literal format diff --git a/modules/fiftyonedegrees/devicedetection/models_test.go b/modules/fiftyonedegrees/devicedetection/models_test.go index 898f25f414..a2a251f425 100644 --- a/modules/fiftyonedegrees/devicedetection/models_test.go +++ b/modules/fiftyonedegrees/devicedetection/models_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/module.go b/modules/fiftyonedegrees/devicedetection/module.go index 78537f999d..603f37810d 100644 --- a/modules/fiftyonedegrees/devicedetection/module.go +++ b/modules/fiftyonedegrees/devicedetection/module.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go b/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go new file mode 100644 index 0000000000..2f4bce4a99 --- /dev/null +++ b/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go @@ -0,0 +1,15 @@ +//go:build !cgo + +package devicedetection + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/stretchr/testify/assert" +) + +func TestBuilderError(t *testing.T) { + _, err := Builder(nil, moduledeps.ModuleDeps{}) + assert.EqualError(t, err, errMsg) +} diff --git a/modules/fiftyonedegrees/devicedetection/module_test.go b/modules/fiftyonedegrees/devicedetection/module_test.go index eb59d01359..19595aca4e 100644 --- a/modules/fiftyonedegrees/devicedetection/module_test.go +++ b/modules/fiftyonedegrees/devicedetection/module_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/no-cgo.go b/modules/fiftyonedegrees/devicedetection/no-cgo.go new file mode 100644 index 0000000000..c9ec89eb20 --- /dev/null +++ b/modules/fiftyonedegrees/devicedetection/no-cgo.go @@ -0,0 +1,16 @@ +//go:build !cgo + +package devicedetection + +import ( + "encoding/json" + "errors" + + "github.com/prebid/prebid-server/v3/modules/moduledeps" +) + +const errMsg = "fiftyonedegrees should not be enabled unless CGO is enabled" + +func Builder(_ json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { + return nil, errors.New(errMsg) +} diff --git a/modules/fiftyonedegrees/devicedetection/request_headers_extractor.go b/modules/fiftyonedegrees/devicedetection/request_headers_extractor.go index 8440886b35..7e36efa295 100644 --- a/modules/fiftyonedegrees/devicedetection/request_headers_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/request_headers_extractor.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/request_headers_extractor_test.go b/modules/fiftyonedegrees/devicedetection/request_headers_extractor_test.go index 77fbed3a42..8cde22c89d 100644 --- a/modules/fiftyonedegrees/devicedetection/request_headers_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/request_headers_extractor_test.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( diff --git a/modules/fiftyonedegrees/devicedetection/sua_payload_extractor.go b/modules/fiftyonedegrees/devicedetection/sua_payload_extractor.go index ab69210449..967ef24d93 100644 --- a/modules/fiftyonedegrees/devicedetection/sua_payload_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/sua_payload_extractor.go @@ -1,3 +1,5 @@ +//go:build cgo + package devicedetection import ( From bdb39036413eede380c4ed18aa31be04d54c5239 Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Tue, 28 Oct 2025 19:37:29 +0200 Subject: [PATCH 117/272] New Adapter: Gravite (#4547) --- static/bidder-info/gravite.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 static/bidder-info/gravite.yaml diff --git a/static/bidder-info/gravite.yaml b/static/bidder-info/gravite.yaml new file mode 100644 index 0000000000..2ff9bcf371 --- /dev/null +++ b/static/bidder-info/gravite.yaml @@ -0,0 +1,6 @@ +aliasOf: 'teqblaze' +endpoint: "https://node1-rtb.gravite.net/pserver" +gvlVendorID: 377 +maintainer: + email: "support@gravite.net" + From 4dc672d1d93f038d23a768e29eea4ea631d6e25a Mon Sep 17 00:00:00 2001 From: Simon Aebli <simon.aebli@goldbach.com> Date: Tue, 28 Oct 2025 19:42:35 +0100 Subject: [PATCH 118/272] New Adapter: Goldbach (#4476) --- adapters/goldbach/goldbach.go | 232 ++++++++++++++++++ adapters/goldbach/goldbach_test.go | 28 +++ .../goldbachtest/exemplary/banner.json | 128 ++++++++++ .../goldbachtest/exemplary/mixed.json | 187 ++++++++++++++ .../exemplary/multiple-publisher.json | 221 +++++++++++++++++ .../goldbachtest/exemplary/native.json | 121 +++++++++ .../goldbachtest/exemplary/video.json | 137 +++++++++++ .../goldbachtest/supplemental/204.json | 72 ++++++ .../goldbachtest/supplemental/500.json | 77 ++++++ .../supplemental/empty-publisher-id.json | 38 +++ .../supplemental/empty-slot-id.json | 38 +++ .../supplemental/invalid-bid-ext.json | 33 +++ .../supplemental/invalid-bidder-ext.json | 35 +++ .../supplemental/invalid-request-ext.json | 81 ++++++ .../supplemental/invalid-response.json | 100 ++++++++ .../supplemental/no-bid-type-response.json | 111 +++++++++ .../supplemental/no-bidder-response.json | 108 ++++++++ adapters/goldbach/params_test.go | 58 +++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_goldbach.go | 35 +++ static/bidder-info/goldbach.yaml | 16 ++ static/bidder-params/goldbach.json | 38 +++ 23 files changed, 1898 insertions(+) create mode 100644 adapters/goldbach/goldbach.go create mode 100644 adapters/goldbach/goldbach_test.go create mode 100644 adapters/goldbach/goldbachtest/exemplary/banner.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/mixed.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/native.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/video.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/204.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/500.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-response.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json create mode 100644 adapters/goldbach/params_test.go create mode 100644 openrtb_ext/imp_goldbach.go create mode 100644 static/bidder-info/goldbach.yaml create mode 100644 static/bidder-params/goldbach.json diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go new file mode 100644 index 0000000000..5c500e63ce --- /dev/null +++ b/adapters/goldbach/goldbach.go @@ -0,0 +1,232 @@ +package goldbach + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type requestExtAdapter struct { + Goldbach requestExtGoldbach `json:"goldbach"` + + *openrtb_ext.ExtRequest `json:"inline,omitempty"` +} + +type requestExtGoldbach struct { + PublisherID string `json:"publisherId"` + MockResponse *bool `json:"mockResponse,omitempty"` +} + +type impExtAdapter struct { + Goldbach impExtGoldbachOutgoing `json:"goldbach"` +} + +type impExtGoldbachOutgoing struct { + Targetings map[string][]string `json:"targetings,omitempty"` + SlotID string `json:"slotId"` +} + +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) { + var reqs []*adapters.RequestData + var errs []error + + var requestExt requestExtAdapter + if request.Ext != nil { + if err := jsonutil.Unmarshal(request.Ext, &requestExt); err != nil { + errs = append(errs, &errortypes.FailedToUnmarshal{Message: fmt.Errorf("unable to unmarshal request.ext: %w", err).Error()}) + } + } + + // group impressions by publisher ID + publisherImps := make(map[string][]openrtb2.Imp) + for _, imp := range request.Imp { + publisherID, impCopy, err := buildImp(imp) + if err != nil { + errs = append(errs, err) + continue + } + + publisherImps[publisherID] = append(publisherImps[publisherID], impCopy) + } + + if len(publisherImps) == 0 { + errs = append(errs, &errortypes.BadInput{Message: "no valid impression found"}) + } + + // create a separate request for each publisher + for publisherID, imps := range publisherImps { + requestPublisher, err := buildRequest(*request, publisherID, imps, &requestExt) + if err != nil { + errs = append(errs, err) + continue + } + + resJSON, err := jsonutil.Marshal(&requestPublisher) + if err != nil { + errs = append(errs, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal request: %w", err).Error()}) + continue + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + req := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: resJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestPublisher.Imp), + } + + reqs = append(reqs, req) + } + + return reqs, errs +} + +func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if httpRes.StatusCode == http.StatusNoContent { + return nil, nil + } + + if httpRes.StatusCode != http.StatusCreated { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", httpRes.StatusCode), + }} + } + + var resp openrtb2.BidResponse + if err := jsonutil.Unmarshal(httpRes.Body, &resp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Errorf("unable to unmarshal response: %w", err).Error(), + }} + } + + bidderResponse := adapters.NewBidderResponse() + bidderResponse.Currency = resp.Cur + + var errs []error + for _, sb := range resp.SeatBid { + for i := range sb.Bid { + bidType, err := getBidMediaType(&sb.Bid[i]) + if err != nil { + errs = append(errs, err) + continue + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + }) + } + } + + if len(bidderResponse.Bids) == 0 { + errs = append(errs, &errortypes.BadServerResponse{ + Message: "no valid bids found in response", + }) + return nil, errs + } + + return bidderResponse, errs +} + +func buildImp(imp openrtb2.Imp) (string, openrtb2.Imp, error) { + impExt, err := extractImpExt(&imp) + if err != nil { + return "", openrtb2.Imp{}, err + } + + targetings := make(map[string][]string) + for key, value := range impExt.CustomTargeting { + targetings[key] = value + } + + imp.Ext, err = jsonutil.Marshal(&impExtAdapter{ + Goldbach: impExtGoldbachOutgoing{ + Targetings: targetings, + SlotID: impExt.SlotID, + }, + }) + + if err != nil { + return "", openrtb2.Imp{}, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal imp.ext: %w", err).Error()} + } + + return impExt.PublisherID, imp, nil +} + +func extractImpExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtGoldbach, error) { + var extImpBidder adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &extImpBidder); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Errorf("unable to unmarshal imp.ext: %w", err).Error(), + } + } + + var goldbachExt openrtb_ext.ImpExtGoldbach + if err := jsonutil.Unmarshal(extImpBidder.Bidder, &goldbachExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Errorf("unable to unmarshal imp.ext.bidder: %w", err).Error(), + } + } + + if len(goldbachExt.PublisherID) == 0 || len(goldbachExt.SlotID) == 0 { + return nil, &errortypes.BadInput{ + Message: "publisherId and slotId are required", + } + } + return &goldbachExt, nil +} + +func buildRequest(request openrtb2.BidRequest, publisherID string, imps []openrtb2.Imp, requestExt *requestExtAdapter) (*openrtb2.BidRequest, error) { + request.Imp = imps + request.ID = fmt.Sprintf("%s_%s", request.ID, publisherID) + + // Set the publisher ID in the request.ext + requestPublisherExt, err := jsonutil.Marshal(&requestExtAdapter{ + Goldbach: requestExtGoldbach{ + PublisherID: publisherID, + MockResponse: requestExt.Goldbach.MockResponse, + }, + ExtRequest: requestExt.ExtRequest, + }) + if err != nil { + return nil, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal request.ext: %w", err).Error()} + } + + request.Ext = requestPublisherExt + + return &request, nil +} + +func getBidMediaType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + var extBid openrtb_ext.ExtBid + if err := jsonutil.Unmarshal(bid.Ext, &extBid); err != nil { + return "", &errortypes.FailedToUnmarshal{Message: fmt.Errorf("unable to unmarshal ext for bid: %w", err).Error()} + } + + if extBid.Prebid == nil || len(extBid.Prebid.Type) == 0 { + return "", &errortypes.BadInput{Message: fmt.Sprintf("no media type for bid %v", bid.ID)} + } + + return extBid.Prebid.Type, nil +} diff --git a/adapters/goldbach/goldbach_test.go b/adapters/goldbach/goldbach_test.go new file mode 100644 index 0000000000..a1f046adfe --- /dev/null +++ b/adapters/goldbach/goldbach_test.go @@ -0,0 +1,28 @@ +package goldbach + +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/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderGoldbach, + config.Adapter{ + Endpoint: "https://gold.bach/prebid/adapter-endpoint", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 1, + DataCenter: "2", + }, + ) + + require.NoError(t, buildErr) + + adapterstest.RunJSONBidderTest(t, "goldbachtest", bidder) +} diff --git a/adapters/goldbach/goldbachtest/exemplary/banner.json b/adapters/goldbach/goldbachtest/exemplary/banner.json new file mode 100644 index 0000000000..23bbc5ef35 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/banner.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": {}, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/mixed.json b/adapters/goldbach/goldbachtest/exemplary/mixed.json new file mode 100644 index 0000000000..2f6995b728 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/mixed.json @@ -0,0 +1,187 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + }, + { + "id": "test-imp-456", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + }, + { + "id": "test-imp-456", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123", "test-imp-456"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + { + "id": "da2048d1-d8a2-425a-9f36-df62e04319ae", + "price": 2.5, + "impid": "test-imp-456", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "da2048d1-d8a2-425a-9f36-df62e04319ae", + "price": 2.5, + "impid": "test-imp-456", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json new file mode 100644 index 0000000000..3ccf106116 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json @@ -0,0 +1,221 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + }, + { + "id": "test-imp-987", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/fr-example.ch/slot-id/some-page", + "publisherId": "fr-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/fr-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-987", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "fr-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_fr-example.ch" + }, + "impIDs": ["test-imp-987"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "cbf0cb64-f86b-4a31-a7c3-3904fa32d168", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-987", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "cbf0cb64-f86b-4a31-a7c3-3904fa32d168", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-987", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/native.json b/adapters/goldbach/goldbachtest/exemplary/native.json new file mode 100644 index 0000000000..2c9c797ca6 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/native.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "id": "test-imp-123", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/video.json b/adapters/goldbach/goldbachtest/exemplary/video.json new file mode 100644 index 0000000000..7eaed83320 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/video.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "imp": [ + { + "video": { + "api": [1, 2], + "mimes": ["video/mp4", "application/javascript"], + "protocols": [2, 3, 5, 6, 7, 8], + "playbackmethod": [6], + "plcmt": 4, + "w": 640, + "h": 480 + }, + "id": "test-imp-123", + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "video": { + "api": [1, 2], + "mimes": ["video/mp4", "application/javascript"], + "protocols": [2, 3, 5, 6, 7, 8], + "playbackmethod": [6], + "plcmt": 4, + "w": 640, + "h": 480 + }, + "id": "test-imp-123", + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "impid": "test-imp-123", + "price": 13.5, + "adm": "test-ad-content", + "adid": "456", + "crid": "1234", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "impid": "test-imp-123", + "price": 13.5, + "adm": "test-ad-content", + "adid": "456", + "crid": "1234", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/204.json b/adapters/goldbach/goldbachtest/supplemental/204.json new file mode 100644 index 0000000000..1a673faa21 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/204.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/500.json b/adapters/goldbach/goldbachtest/supplemental/500.json new file mode 100644 index 0000000000..3922de7f01 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/500.json @@ -0,0 +1,77 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json new file mode 100644 index 0000000000..f034a24652 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "publisherId and slotId are required", + "comparison": "literal" + }, + { + "value": "no valid impression found", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json new file mode 100644 index 0000000000..05ffb09d63 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "publisherId and slotId are required", + "comparison": "literal" + }, + { + "value": "no valid impression found", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json new file mode 100644 index 0000000000..e23fab6614 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": "invalid bid ext" + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "^unable to unmarshal imp.ext:", + "comparison": "regex" + }, + { + "value": "no valid impression found", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json new file mode 100644 index 0000000000..ac704eb422 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json @@ -0,0 +1,35 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": "invalid bid ext" + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "^unable to unmarshal imp.ext.bidder:", + "comparison": "regex" + }, + { + "value": "no valid impression found", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json new file mode 100644 index 0000000000..3ea36effc0 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": "invalid request ext" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "^unable to unmarshal request.ext:", + "comparison": "regex" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-response.json b/adapters/goldbach/goldbachtest/supplemental/invalid-response.json new file mode 100644 index 0000000000..b7dd6210b7 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-response.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "^unable to unmarshal response:", + "comparison": "regex" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json b/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json new file mode 100644 index 0000000000..9379a056a8 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": {} + } + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "no media type for bid test-bid-123", + "comparison": "literal" + }, + { + "value": "no valid bids found in response", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json new file mode 100644 index 0000000000..b045343fa6 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234" + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "^unable to unmarshal ext for bid:", + "comparison": "regex" + }, + { + "value": "no valid bids found in response", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/params_test.go b/adapters/goldbach/params_test.go new file mode 100644 index 0000000000..b03d182247 --- /dev/null +++ b/adapters/goldbach/params_test.go @@ -0,0 +1,58 @@ +package goldbach + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/require" +) + +// This file actually intends to test static/bidder-params/goldbach.json + +// TestValidParams makes sure that the goldbach schema accepts all imp.ext fields which we intend to support. + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas. %v", err) + + for _, validParam := range validParams { + err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(validParam)) + + require.NoError(t, err, "Schema rejected goldbach params: %s", validParam) + } +} + +// TestInvalidParams makes sure that the goldbach schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas. %v", err) + + for _, invalidParam := range invalidParams { + err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(invalidParam)) + require.Error(t, err, "Schema allowed unexpected params: %s", invalidParam) + } +} + +var validParams = []string{ + `{"publisherId":"123","slotId":"333"}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":["value2","value3"]}}`, +} + +var invalidParams = []string{ + `4.2`, + `5`, + `[]`, + ``, + `null`, + `true`, + `{}`, + `{"publisherId":123,"slotId":"333"}`, + `{"publisherId":"123","slotId":333}`, + `{"publisherId":"1234"}`, + `{"slotId":"abc"}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":123,"key2":["value2","value3"]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":false,"key2":["value2","value3"]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":[123,456]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":[true,false]}}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e025eb0ed3..3b33a75b18 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -114,6 +114,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/gamma" "github.com/prebid/prebid-server/v3/adapters/gamoshi" "github.com/prebid/prebid-server/v3/adapters/globalsun" + "github.com/prebid/prebid-server/v3/adapters/goldbach" "github.com/prebid/prebid-server/v3/adapters/gothamads" "github.com/prebid/prebid-server/v3/adapters/grid" "github.com/prebid/prebid-server/v3/adapters/gumgum" @@ -380,6 +381,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderGamma: gamma.Builder, openrtb_ext.BidderGamoshi: gamoshi.Builder, openrtb_ext.BidderGlobalsun: globalsun.Builder, + openrtb_ext.BidderGoldbach: goldbach.Builder, openrtb_ext.BidderGothamads: gothamads.Builder, openrtb_ext.BidderGrid: grid.Builder, openrtb_ext.BidderGumGum: gumgum.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index cdb6dcd2c7..c830494330 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -131,6 +131,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderGamma, BidderGamoshi, BidderGlobalsun, + BidderGoldbach, BidderGothamads, BidderGrid, BidderGumGum, @@ -503,6 +504,7 @@ const ( BidderGamma BidderName = "gamma" BidderGamoshi BidderName = "gamoshi" BidderGlobalsun BidderName = "globalsun" + BidderGoldbach BidderName = "goldbach" BidderGothamads BidderName = "gothamads" BidderGrid BidderName = "grid" BidderGumGum BidderName = "gumgum" diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go new file mode 100644 index 0000000000..238ef2ff2e --- /dev/null +++ b/openrtb_ext/imp_goldbach.go @@ -0,0 +1,35 @@ +package openrtb_ext + +import ( + "fmt" + + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type ImpExtGoldbach struct { + PublisherID string `json:"publisherId"` + SlotID string `json:"slotId"` + CustomTargeting map[string]stringOrStringArray `json:"customTargeting,omitempty"` +} + +// stringOrStringArray is a custom type that can hold either a single value of type T or an array of values of type T. +type stringOrStringArray []string + +func (t *stringOrStringArray) UnmarshalJSON(b []byte) error { + // try to unmarshal as a single value of type T first + var itemResult string + if err := jsonutil.UnmarshalValid(b, &itemResult); err == nil { + *t = []string{itemResult} + return nil + } + + // then try to unmarshal as an array of type T + var arrayResult []string + if err := jsonutil.UnmarshalValid(b, &arrayResult); err == nil { + *t = arrayResult + return nil + } + + // if both attempts fail, return an error + return fmt.Errorf("value should be of type %T or %T", itemResult, arrayResult) +} diff --git a/static/bidder-info/goldbach.yaml b/static/bidder-info/goldbach.yaml new file mode 100644 index 0000000000..08d43ba216 --- /dev/null +++ b/static/bidder-info/goldbach.yaml @@ -0,0 +1,16 @@ +endpoint: "https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction" +endpointCompression: gzip +maintainer: + email: "engineering@goldbach.com" +gvlVendorID: 580 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/goldbach.json b/static/bidder-params/goldbach.json new file mode 100644 index 0000000000..8958db13cf --- /dev/null +++ b/static/bidder-params/goldbach.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Goldbach Adapter Params", + "description": "A schema which validates params accepted by the Goldbach adapter", + + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "minLength": 1, + "description": "Publisher Environment ID" + }, + "slotId": { + "type": "string", + "minLength": 1, + "description": "Slot Id" + }, + "customTargeting": { + "type": "object", + "description": "Custom Targeting Parameters", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + } + }, + + "required": ["publisherId", "slotId"] +} From 6df9618595f53aee00cf720310d78466d492637a Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic <ficadub@gmail.com> Date: Wed, 29 Oct 2025 21:40:39 +0100 Subject: [PATCH 119/272] New Adapter: Showheroes (#4533) --- adapters/showheroes/params_test.go | 51 ++++ adapters/showheroes/showheroes.go | 223 ++++++++++++++++++ adapters/showheroes/showheroes_test.go | 20 ++ .../exemplary/simple-banner-inapp.json | 159 +++++++++++++ .../simple-banner-multiple-bids.json | 203 ++++++++++++++++ .../exemplary/simple-banner.json | 141 +++++++++++ .../exemplary/simple-video.json | 133 +++++++++++ .../204-response-from-target.json | 104 ++++++++ .../400-response-from-target.json | 111 +++++++++ .../supplemental/foreign-currency.json | 100 ++++++++ .../supplemental/invalid-mtype.json | 141 +++++++++++ .../supplemental/invalid-unit-id.json | 44 ++++ .../supplemental/missing-bundle.json | 38 +++ .../supplemental/missing-page-url.json | 44 ++++ .../supplemental/missing-site-and-app.json | 37 +++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_showheroes.go | 5 + static/bidder-info/showheroes-bs.yaml | 1 + static/bidder-info/showheroes.yaml | 15 ++ static/bidder-info/showheroesBs.yaml | 1 + static/bidder-params/showheroes.json | 14 ++ 22 files changed, 1589 insertions(+) create mode 100644 adapters/showheroes/params_test.go create mode 100644 adapters/showheroes/showheroes.go create mode 100644 adapters/showheroes/showheroes_test.go create mode 100644 adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json create mode 100644 adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json create mode 100644 adapters/showheroes/showheroestest/exemplary/simple-banner.json create mode 100644 adapters/showheroes/showheroestest/exemplary/simple-video.json create mode 100644 adapters/showheroes/showheroestest/supplemental/204-response-from-target.json create mode 100644 adapters/showheroes/showheroestest/supplemental/400-response-from-target.json create mode 100644 adapters/showheroes/showheroestest/supplemental/foreign-currency.json create mode 100644 adapters/showheroes/showheroestest/supplemental/invalid-mtype.json create mode 100644 adapters/showheroes/showheroestest/supplemental/invalid-unit-id.json create mode 100644 adapters/showheroes/showheroestest/supplemental/missing-bundle.json create mode 100644 adapters/showheroes/showheroestest/supplemental/missing-page-url.json create mode 100644 adapters/showheroes/showheroestest/supplemental/missing-site-and-app.json create mode 100644 openrtb_ext/imp_showheroes.go create mode 100644 static/bidder-info/showheroes-bs.yaml create mode 100644 static/bidder-info/showheroes.yaml create mode 100644 static/bidder-info/showheroesBs.yaml create mode 100644 static/bidder-params/showheroes.json diff --git a/adapters/showheroes/params_test.go b/adapters/showheroes/params_test.go new file mode 100644 index 0000000000..a22693f81a --- /dev/null +++ b/adapters/showheroes/params_test.go @@ -0,0 +1,51 @@ +package showheroes + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderShowheroes, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the JSON schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderShowheroes, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"unitId": "12345678"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"unitId": ""}`, + `{"unitId": "short"}`, + `{"unitId": 123345678}`, +} diff --git a/adapters/showheroes/showheroes.go b/adapters/showheroes/showheroes.go new file mode 100644 index 0000000000..f04adc100d --- /dev/null +++ b/adapters/showheroes/showheroes.go @@ -0,0 +1,223 @@ +package showheroes + +import ( + "encoding/json" + "fmt" + "net/http" + + "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" + "github.com/prebid/prebid-server/v3/version" +) + +type adapter struct { + endpoint string +} + +type shExtImpBidder struct { + Prebid *openrtb_ext.ExtImpPrebid `json:"prebid,omitempty"` + Bidder openrtb_ext.ExtImpShowheroes `json:"bidder,omitempty"` + Gpid string `json:"gpid,omitempty"` + Tid string `json:"tid,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + Params openrtb_ext.ExtImpShowheroes `json:"params"` +} + +// Builder builds a new instance of the Showheroes adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{ + endpoint: config.Endpoint, + }, nil +} + +func validate(request *openrtb2.BidRequest) error { + if request.Site != nil && request.Site.Page == "" { + return &errortypes.BadInput{ + Message: "site request doesn't have a page URL", + } + } + + if request.App != nil && request.App.Bundle == "" { + return &errortypes.BadInput{ + Message: "app request doesn't have a bundle ID", + } + } + + if request.Site == nil && request.App == nil { + return &errortypes.BadInput{ + Message: "request must contain a site or an app", + } + } + + return nil +} + +func processImp(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { + var bidderExt shExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return &errortypes.BadInput{ + Message: "Error parsing bidder params", + } + } + + // move params from .bidder to .params + // this is required since openrtb_ext.ExtImpShowheroes is used in 2 places: + // 1. shExtImpBidder.Bidder - for parsing the incoming request + // 2. shExtImpBidder.Params - for marshaling the outgoing request to showheroes + bidderExt.Params.UnitID = bidderExt.Bidder.UnitID + + impExt, err := jsonutil.Marshal(bidderExt) + if err != nil { + return err + } + imp.Ext = impExt + + if imp.BidFloor == 0 || imp.BidFloorCur == "EUR" { + return nil + } + + currency := imp.BidFloorCur + if currency == "" { + currency = "USD" + } + + eurFloor, err := reqInfo.ConvertCurrency(imp.BidFloor, currency, "EUR") + if err != nil { + return err + } + + imp.BidFloor = eurFloor + imp.BidFloorCur = "EUR" + + return nil +} + +func getPrebidChannel(request *openrtb2.BidRequest) (string, string) { + var channelName string + var channelVersion string + reqExt := &openrtb_ext.ExtRequest{} + + if err := jsonutil.Unmarshal(request.Ext, reqExt); err == nil && reqExt.Prebid.Channel != nil { + channelName = reqExt.Prebid.Channel.Name + channelVersion = reqExt.Prebid.Channel.Version + } + return channelName, channelVersion +} + +func setPBSVersion(request *openrtb2.BidRequest, pbsVersion string) { + if pbsVersion == "" { + pbsVersion = version.VerUnknown + } + source := request.Source + if source == nil { + source = &openrtb2.Source{} + request.Source = source + } + + sourceExtMap := make(map[string]json.RawMessage) + if source.Ext != nil { + if err := jsonutil.Unmarshal(source.Ext, &sourceExtMap); err != nil { + return + } + } + sourceExtMap["pbs"] = json.RawMessage(`{"pbsv":"` + pbsVersion + `", "pbsp": "go"}`) + if ext, err := json.Marshal(sourceExtMap); err == nil { + source.Ext = ext + } +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, extra *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if err := validate(request); err != nil { + return nil, []error{err} + } + var errors []error + validImps := make([]openrtb2.Imp, 0, len(request.Imp)) + + prebidChannelName, channelVersion := getPrebidChannel(request) + + for _, imp := range request.Imp { + if err := processImp(&imp, extra); err != nil { + errors = append(errors, err) + continue + } + + if imp.DisplayManager == "" { + imp.DisplayManager = prebidChannelName + imp.DisplayManagerVer = channelVersion + } + validImps = append(validImps, imp) + } + + if len(validImps) == 0 { + return nil, errors + } + + setPBSVersion(request, version.Ver) + + request.Imp = validImps + reqJSON, err := json.Marshal(request) + if err != nil { + errors = append(errors, err) + return nil, errors + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return []*adapters.RequestData{ + { + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, + }, errors +} + +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 bidResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResponse); err != nil { + return nil, []error{err} + } + + bidderResponse := adapters.NewBidderResponse() + bidderResponse.Currency = bidResponse.Cur + + for _, seatBid := range bidResponse.SeatBid { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + + b := &adapters.TypedBid{ + Bid: bid, + BidType: getBidType(bid.MType), + } + bidderResponse.Bids = append(bidderResponse.Bids, b) + } + } + + return bidderResponse, nil +} + +func getBidType(markupType openrtb2.MarkupType) openrtb_ext.BidType { + + switch markupType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo + default: + return openrtb_ext.BidTypeVideo + } +} diff --git a/adapters/showheroes/showheroes_test.go b/adapters/showheroes/showheroes_test.go new file mode 100644 index 0000000000..64f8e62f2f --- /dev/null +++ b/adapters/showheroes/showheroes_test.go @@ -0,0 +1,20 @@ +package showheroes + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderShowheroes, config.Adapter{ + Endpoint: "https://bid.showheroes.com/api/v1/bid", + }, config.Server{}) + if err != nil { + t.Fatalf("Builder returned unexpected error %v", err) + } + + adapterstest.RunJSONBidderTest(t, "showheroestest", bidder) +} diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json b/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json new file mode 100644 index 0000000000..b3317ea44e --- /dev/null +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json @@ -0,0 +1,159 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.showheroes.app", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ], + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "unitId": "12345678" + } + } + } + ], + "ext": { + "prebid": { + "channel": { + "name": "prebidjs", + "version": "1.0" + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.showheroes.app", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ], + "w": 320, + "h": 50 + }, + "displaymanager": "prebidjs", + "displaymanagerver": "1.0", + "ext": { + "bidder": { + "unitId": "12345678" + }, + "params": { + "unitId": "12345678" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + }, + "ext": { + "prebid": { + "channel": { + "name": "prebidjs", + "version": "1.0" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.3, + "crid": "creative-789", + "adm": "<img src='https://creative-url.showheroes.com/banner.jpg'>", + "w": 320, + "h": 50, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.3, + "crid": "creative-789", + "adm": "<img src='https://creative-url.showheroes.com/banner.jpg'>", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json b/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json new file mode 100644 index 0000000000..42489d40fc --- /dev/null +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json @@ -0,0 +1,203 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "12345678" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ], + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "unitId": "87654321" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "12345678" + }, + "params": { + "unitId": "12345678" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ], + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "unitId": "87654321" + }, + "params": { + "unitId": "87654321" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id-1", "test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id-1", + "impid": "test-imp-id-1", + "price": 0.1, + "crid": "creative-123", + "adm": "<iframe src='https://creative-url.showheroes.com/medium-rectangle'></iframe>", + "w": 300, + "h": 250, + "mtype": 1 + }, + { + "id": "test-bid-id-2", + "impid": "test-imp-id-2", + "price": 0.15, + "crid": "creative-456", + "adm": "<iframe src='https://creative-url.showheroes.com/leaderboard'></iframe>", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id-1", + "impid": "test-imp-id-1", + "price": 0.1, + "crid": "creative-123", + "adm": "<iframe src='https://creative-url.showheroes.com/medium-rectangle'></iframe>", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "test-bid-id-2", + "impid": "test-imp-id-2", + "price": 0.15, + "crid": "creative-456", + "adm": "<iframe src='https://creative-url.showheroes.com/leaderboard'></iframe>", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner.json b/adapters/showheroes/showheroestest/exemplary/simple-banner.json new file mode 100644 index 0000000000..c0b3dc4a4f --- /dev/null +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "12345678" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "12345678" + }, + "params": { + "unitId": "12345678" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "<iframe id='789abc' name='789abc' src='https://creative-url.showheroes.com'></iframe>", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "<iframe id='789abc' name='789abc' src='https://creative-url.showheroes.com'></iframe>", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/showheroes/showheroestest/exemplary/simple-video.json b/adapters/showheroes/showheroestest/exemplary/simple-video.json new file mode 100644 index 0000000000..65f10ee940 --- /dev/null +++ b/adapters/showheroes/showheroestest/exemplary/simple-video.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6] + }, + "ext": { + "bidder": { + "unitId": "12345678" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6] + }, + "ext": { + "bidder": { + "unitId": "12345678" + }, + "params": { + "unitId": "12345678" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.2, + "crid": "creative-456", + "adm": "<VAST version='3.0'><Ad id='123'><InLine><AdSystem>ShowHeroes</AdSystem></InLine></Ad></VAST>", + "w": 640, + "h": 480, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.2, + "crid": "creative-456", + "adm": "<VAST version='3.0'><Ad id='123'><InLine><AdSystem>ShowHeroes</AdSystem></InLine></Ad></VAST>", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/204-response-from-target.json b/adapters/showheroes/showheroestest/supplemental/204-response-from-target.json new file mode 100644 index 0000000000..5f3f099f43 --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/204-response-from-target.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "invalid-unit-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "invalid-unit-id" + }, + "params": { + "unitId": "invalid-unit-id" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/showheroes/showheroestest/supplemental/400-response-from-target.json b/adapters/showheroes/showheroestest/supplemental/400-response-from-target.json new file mode 100644 index 0000000000..322498b8e8 --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/400-response-from-target.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + }, + "params": { + "unitId": "123456" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": { + "message": "Bad request" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unexpected status code: 400", + "comparison": "literal" + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/foreign-currency.json b/adapters/showheroes/showheroestest/supplemental/foreign-currency.json new file mode 100644 index 0000000000..c70af4dd9f --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/foreign-currency.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "cur": ["USD"], + "site": { + "page": "https://usa.site/url" + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "bidfloor": 1.0, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "unitId": "12345678" + } + } + }], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 0.5 + }, + "USD": { + "EUR": 2.0 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "body": { + "id": "test-request-id", + "cur": ["USD"], + "site": { + "page": "https://usa.site/url" + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "bidfloor": 2.0, + "bidfloorcur": "EUR", + "ext": { + "bidder": { + "unitId": "12345678" + }, + "params": { + "unitId": "12345678" + } + } + }], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 0.5 + }, + "USD": { + "EUR": 2.0 + } + }, + "usepbsrates": false + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} diff --git a/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json b/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json new file mode 100644 index 0000000000..36511514fd --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.showheroes.com/api/v1/bid", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "showheroes.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + }, + "params": { + "unitId": "123456" + } + } + } + ], + "source": { + "ext": { + "pbs": { + "pbsp": "go", + "pbsv": "unknown" + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "<VAST version='3.0'><Ad id='123'><InLine><AdSystem>ShowHeroes</AdSystem></InLine></Ad></VAST>", + "w": 300, + "h": 250, + "mtype": 5 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "<VAST version='3.0'><Ad id='123'><InLine><AdSystem>ShowHeroes</AdSystem></InLine></Ad></VAST>", + "w": 300, + "h": 250, + "mtype": 5 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/invalid-unit-id.json b/adapters/showheroes/showheroestest/supplemental/invalid-unit-id.json new file mode 100644 index 0000000000..83dc147b07 --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/invalid-unit-id.json @@ -0,0 +1,44 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "this_id_will_be_replaced" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": 123456 + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Error parsing bidder params", + "comparison": "literal" + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/missing-bundle.json b/adapters/showheroes/showheroestest/supplemental/missing-bundle.json new file mode 100644 index 0000000000..c85ac0d62c --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/missing-bundle.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "app request doesn't have a bundle ID", + "comparison": "literal" + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/missing-page-url.json b/adapters/showheroes/showheroestest/supplemental/missing-page-url.json new file mode 100644 index 0000000000..ec2c08d601 --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/missing-page-url.json @@ -0,0 +1,44 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "site request doesn't have a page URL", + "comparison": "literal" + } + ] +} diff --git a/adapters/showheroes/showheroestest/supplemental/missing-site-and-app.json b/adapters/showheroes/showheroestest/supplemental/missing-site-and-app.json new file mode 100644 index 0000000000..f0a555eb73 --- /dev/null +++ b/adapters/showheroes/showheroestest/supplemental/missing-site-and-app.json @@ -0,0 +1,37 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "unitId": "123456" + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "request must contain a site or an app", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 3b33a75b18..aa578b089f 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -205,6 +205,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" "github.com/prebid/prebid-server/v3/adapters/seedtag" "github.com/prebid/prebid-server/v3/adapters/sharethrough" + "github.com/prebid/prebid-server/v3/adapters/showheroes" "github.com/prebid/prebid-server/v3/adapters/silvermob" "github.com/prebid/prebid-server/v3/adapters/silverpush" "github.com/prebid/prebid-server/v3/adapters/smaato" @@ -474,6 +475,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSaLunaMedia: salunamedia.Builder, openrtb_ext.BidderScreencore: screencore.Builder, openrtb_ext.BidderSharethrough: sharethrough.Builder, + openrtb_ext.BidderShowheroes: showheroes.Builder, openrtb_ext.BidderSilverMob: silvermob.Builder, openrtb_ext.BidderSilverPush: silverpush.Builder, openrtb_ext.BidderSmaato: smaato.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index c830494330..4469ed3f2f 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -223,6 +223,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSaLunaMedia, BidderScreencore, BidderSharethrough, + BidderShowheroes, BidderSilverMob, BidderSilverPush, BidderSmaato, @@ -596,6 +597,7 @@ const ( BidderSaLunaMedia BidderName = "sa_lunamedia" BidderScreencore BidderName = "screencore" BidderSharethrough BidderName = "sharethrough" + BidderShowheroes BidderName = "showheroes" BidderSilverMob BidderName = "silvermob" BidderSilverPush BidderName = "silverpush" BidderSmaato BidderName = "smaato" diff --git a/openrtb_ext/imp_showheroes.go b/openrtb_ext/imp_showheroes.go new file mode 100644 index 0000000000..3e9d2ae0ea --- /dev/null +++ b/openrtb_ext/imp_showheroes.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpShowheroes struct { + UnitID string `json:"unitId"` +} diff --git a/static/bidder-info/showheroes-bs.yaml b/static/bidder-info/showheroes-bs.yaml new file mode 100644 index 0000000000..4b49a60f18 --- /dev/null +++ b/static/bidder-info/showheroes-bs.yaml @@ -0,0 +1 @@ +aliasOf: "showheroes" \ No newline at end of file diff --git a/static/bidder-info/showheroes.yaml b/static/bidder-info/showheroes.yaml new file mode 100644 index 0000000000..29296ecd91 --- /dev/null +++ b/static/bidder-info/showheroes.yaml @@ -0,0 +1,15 @@ +endpoint: "https://ads.viralize.tv/openrtb2/auction/" +maintainer: + email: tech@showheroes.com +gvlVendorID: 111 +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video diff --git a/static/bidder-info/showheroesBs.yaml b/static/bidder-info/showheroesBs.yaml new file mode 100644 index 0000000000..4b49a60f18 --- /dev/null +++ b/static/bidder-info/showheroesBs.yaml @@ -0,0 +1 @@ +aliasOf: "showheroes" \ No newline at end of file diff --git a/static/bidder-params/showheroes.json b/static/bidder-params/showheroes.json new file mode 100644 index 0000000000..3c269d118d --- /dev/null +++ b/static/bidder-params/showheroes.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Showheroes Adapter Params", + "description": "A schema which validates params accepted by the Showheroes adapter", + "type": "object", + "properties": { + "unitId": { + "type": "string", + "description": "Unit ID", + "minLength": 8 + } + }, + "required": ["unitId"] +} From 21e0f06a3ffac317cd710c23a3b7742cb1939c8c Mon Sep 17 00:00:00 2001 From: quietPusher <129727954+quietPusher@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:59:56 +0100 Subject: [PATCH 120/272] New Adapter: Performist - Limelight Alias (#4283) --- static/bidder-info/performist.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/performist.yaml diff --git a/static/bidder-info/performist.yaml b/static/bidder-info/performist.yaml new file mode 100644 index 0000000000..82ae442c06 --- /dev/null +++ b/static/bidder-info/performist.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.performserv.com/openrtb/{{.PublisherID}}" +aliasOf: "limelightDigital" From 85f6a6b5eaec5ab656667e82c46ab8ec920dc33a Mon Sep 17 00:00:00 2001 From: Karim Mourra <karim@jwplayer.com> Date: Mon, 3 Nov 2025 12:48:47 -0300 Subject: [PATCH 121/272] Connatix: Support GZIP (#4575) --- static/bidder-info/connatix.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/connatix.yaml b/static/bidder-info/connatix.yaml index 6759b7ef4d..9c8ecbb254 100644 --- a/static/bidder-info/connatix.yaml +++ b/static/bidder-info/connatix.yaml @@ -1,4 +1,5 @@ endpoint: "https://capi.connatix.com/rtb/ortb" +endpointCompression: gzip maintainer: email: "pubsolutions@connatix.com" gvlVendorID: 143 From 2e97ad7e82874a197b60297083e595a7364dedb3 Mon Sep 17 00:00:00 2001 From: Piotr Jaworski <109736938+piotrj-rtbh@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:55:28 +0100 Subject: [PATCH 122/272] RTBHouse: PMP removal, publisherId parameter extraction (#4564) --- adapters/rtbhouse/rtbhouse.go | 92 +++++++++- .../exemplary/ae-igs-removal.json | 118 ++++++++++++ .../exemplary/app-with-publisher.json | 118 ++++++++++++ .../bidfloor-as-bidder-param-without-cur.json | 9 + .../exemplary/bidfloor-as-bidder-param.json | 9 + .../bidfloor-as-impbidfloor-with-cur.json | 9 + .../bidfloor-as-impbidfloor-without-cur.json | 9 + .../existing-site-publisher-override.json | 122 +++++++++++++ .../multiple-imps-different-publishers.json | 171 ++++++++++++++++++ .../exemplary/pmp-removal-test.json | 121 +++++++++++++ ...bidfloors-given-param-and-impbidfloor.json | 9 + .../supplemental/malformed-imp-ext.json | 25 +++ 12 files changed, 808 insertions(+), 4 deletions(-) create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json create mode 100644 adapters/rtbhouse/rtbhousetest/supplemental/malformed-imp-ext.json diff --git a/adapters/rtbhouse/rtbhouse.go b/adapters/rtbhouse/rtbhouse.go index 9a7e3f4f92..c6445f1f15 100644 --- a/adapters/rtbhouse/rtbhouse.go +++ b/adapters/rtbhouse/rtbhouse.go @@ -21,6 +21,16 @@ const ( BidderCurrency string = "USD" ) +// publisherExtPrebid defines the structure for publisher.ext.prebid used by RTBHouse adapter +type publisherExtPrebid struct { + PublisherId string `json:"publisherId,omitempty"` +} + +// publisherExt defines the structure for publisher.ext used by RTBHouse adapter +type publisherExt struct { + Prebid *publisherExtPrebid `json:"prebid,omitempty"` +} + // RTBHouseAdapter implements the Bidder interface. type RTBHouseAdapter struct { endpoint string @@ -45,14 +55,23 @@ func (adapter *RTBHouseAdapter) MakeRequests( reqCopy := *openRTBRequest reqCopy.Imp = []openrtb2.Imp{} + + var publisherId string + for _, imp := range openRTBRequest.Imp { + rtbhouseExt, err := getImpressionExt(imp) + if err != nil { + return nil, []error{err} + } + + // Extract publisherId from the first impression that has one + if publisherId == "" && rtbhouseExt.PublisherId != "" { + publisherId = rtbhouseExt.PublisherId + } + var bidFloorCur = imp.BidFloorCur var bidFloor = imp.BidFloor if bidFloorCur == "" && bidFloor == 0 { - rtbhouseExt, err := getImpressionExt(imp) - if err != nil { - return nil, []error{err} - } if rtbhouseExt.BidFloor > 0 { bidFloor = rtbhouseExt.BidFloor bidFloorCur = BidderCurrency @@ -90,11 +109,22 @@ func (adapter *RTBHouseAdapter) MakeRequests( } imp.Ext = newImpExt + // Remove PMP from impression + imp.PMP = nil + // Set the CUR of bid to BIDDER_CURRENCY after converting all floors reqCopy.Cur = []string{BidderCurrency} reqCopy.Imp = append(reqCopy.Imp, imp) } + // Set publisher ID in site.publisher.ext.prebid.publisherId or app.publisher.ext.prebid.publisherId if we found one + if publisherId != "" { + if err := setPublisherID(&reqCopy, publisherId); err != nil { + errs = append(errs, err) + return nil, errs + } + } + openRTBRequestJSON, err := json.Marshal(reqCopy) if err != nil { errs = append(errs, err) @@ -115,6 +145,60 @@ func (adapter *RTBHouseAdapter) MakeRequests( return requestsToBidder, errs } +// setPublisherID sets the publisherId in site.publisher.ext.prebid.publisherId or app.publisher.ext.prebid.publisherId +func setPublisherID(request *openrtb2.BidRequest, publisherId string) error { + var publisher *openrtb2.Publisher + if request.Site != nil { + // Create a copy of the site to avoid modifying the original request + siteCopy := *request.Site + request.Site = &siteCopy + publisher = request.Site.Publisher + } else if request.App != nil { + // Create a copy of the app to avoid modifying the original request + appCopy := *request.App + request.App = &appCopy + publisher = request.App.Publisher + } else { + // If neither site nor app exists, create a site object + request.Site = &openrtb2.Site{} + } + + if publisher != nil { + // Create a copy of the publisher to avoid modifying the original request + publisherCopy := *publisher + publisher = &publisherCopy + } else { + publisher = &openrtb2.Publisher{} + } + + // Set publisherId in publisher.ext.prebid.publisherId using local struct + var pubExt publisherExt + if publisher.Ext != nil { + if err := jsonutil.Unmarshal(publisher.Ext, &pubExt); err != nil { + return err + } + } + if pubExt.Prebid == nil { + pubExt.Prebid = &publisherExtPrebid{} + } + pubExt.Prebid.PublisherId = publisherId + + publisherExtJSON, err := jsonutil.Marshal(pubExt) + if err != nil { + return err + } + publisher.Ext = publisherExtJSON + + // Assign the updated publisher back to the appropriate object + if request.Site != nil { + request.Site.Publisher = publisher + } else if request.App != nil { + request.App.Publisher = publisher + } + + return nil +} + func clearAuctionEnvironment(imp *openrtb2.Imp) (json.RawMessage, error) { var objmap map[string]interface{} err := json.Unmarshal(imp.Ext, &objmap) diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json b/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json new file mode 100644 index 0000000000..7cf35414aa --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "ae": 1, + "igs": { + "biddable": 1 + }, + "bidder": { + "publisherId": "12345" + }, + "someOtherField": "should-remain" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + }, + "someOtherField": "should-remain" + }, + "id": "test-imp-id" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json b/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json new file mode 100644 index 0000000000..d53ab37f2d --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.example.app", + "name": "Test App" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "app-publisher-123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "app": { + "bundle": "com.example.app", + "name": "Test App", + "publisher": { + "ext": { + "prebid": { + "publisherId": "app-publisher-123" + } + } + } + }, + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "app-publisher-123" + } + }, + "id": "test-imp-id" + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json index 9b0f8d3e38..d31110cb3e 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json @@ -63,6 +63,15 @@ "id": "test-imp-id" } ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + }, "ext": { "prebid": { "currency": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json index c6a82faa57..fd324fb034 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json @@ -66,6 +66,15 @@ "id": "test-imp-id" } ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + }, "ext": { "prebid": { "currency": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json index b0b34a25af..24cc0822dd 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json @@ -63,6 +63,15 @@ "id": "test-imp-id" } ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + }, "ext": { "prebid": { "currency": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json index a6dbcec864..e579017c07 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json @@ -61,6 +61,15 @@ "id": "test-imp-id" } ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + }, "ext": { "prebid": { "currency": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json b/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json new file mode 100644 index 0000000000..235e2c4a8b --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com", + "publisher": { + "id": "existing-publisher", + "name": "Existing Publisher" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "new-publisher-123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "existing-publisher", + "name": "Existing Publisher", + "ext": { + "prebid": { + "publisherId": "new-publisher-123" + } + } + } + }, + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "new-publisher-123" + } + }, + "id": "test-imp-id" + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json b/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json new file mode 100644 index 0000000000..3cb44d5422 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json @@ -0,0 +1,171 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "first-publisher" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "second-publisher" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "first-publisher" + } + }, + "id": "test-imp-id-1" + }, + { + "banner": { + "format": [ + { + "h": 90, + "w": 728 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "second-publisher" + } + }, + "id": "test-imp-id-2" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "first-publisher" + } + } + } + } + }, + "impIDs": ["test-imp-id-1", "test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid1", + "impid": "test-imp-id-1", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad-1", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + { + "id": "randomid2", + "impid": "test-imp-id-2", + "price": 150, + "adid": "87654321", + "adm": "some-test-ad-2", + "cid": "789", + "crid": "87654321", + "h": 90, + "w": 728, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid1", + "impid": "test-imp-id-1", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad-1", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "randomid2", + "impid": "test-imp-id-2", + "price": 150, + "adid": "87654321", + "adm": "some-test-ad-2", + "cid": "789", + "crid": "87654321", + "h": 90, + "w": 728, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json b/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json new file mode 100644 index 0000000000..0d31ef3d5b --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "pmp": { + "deals": [ + { + "id": "deal-id-1", + "bidfloor": 5.00, + "bidfloorcur": "USD" + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + } + }, + "id": "test-imp-id" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json b/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json index 7b9ebf9685..71b95d18db 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json @@ -65,6 +65,15 @@ "id": "test-imp-id" } ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + }, "ext": { "prebid": { "currency": { diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/malformed-imp-ext.json b/adapters/rtbhouse/rtbhousetest/supplemental/malformed-imp-ext.json new file mode 100644 index 0000000000..655f71899e --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/supplemental/malformed-imp-ext.json @@ -0,0 +1,25 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": "invalid-json" + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Bidder extension not provided or can't be unmarshalled", + "comparison": "literal" + } + ] +} \ No newline at end of file From e672d127b728dc26244dc346d9379ef1b59a86ff Mon Sep 17 00:00:00 2001 From: Mikael Lundin <mikael-lundin@users.noreply.github.com> Date: Tue, 11 Nov 2025 04:07:45 +0100 Subject: [PATCH 123/272] Adnuntius: Pass targeting to ad server (#4545) --- adapters/adnuntius/adnuntius_types.go | 17 ++- adapters/adnuntius/adnuntius_utils.go | 21 +++ .../supplemental/targeting-fields.json | 122 ++++++++++++++++++ openrtb_ext/imp_adnuntius.go | 9 +- 4 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 adapters/adnuntius/adnuntiustest/supplemental/targeting-fields.json diff --git a/adapters/adnuntius/adnuntius_types.go b/adapters/adnuntius/adnuntius_types.go index 17d81cd6a0..e65a4ddb0b 100644 --- a/adapters/adnuntius/adnuntius_types.go +++ b/adapters/adnuntius/adnuntius_types.go @@ -18,12 +18,17 @@ type NativeRequest struct { } type adnRequestAdunit struct { - AuId string `json:"auId"` - TargetId string `json:"targetId"` - AdType string `json:"adType,omitempty"` - NativeRequest NativeRequest `json:"nativeRequest,omitempty"` - Dimensions [][]int64 `json:"dimensions,omitempty"` - MaxDeals int `json:"maxDeals,omitempty"` + AuId string `json:"auId"` + TargetId string `json:"targetId"` + AdType string `json:"adType,omitempty"` + NativeRequest NativeRequest `json:"nativeRequest,omitempty"` + Dimensions [][]int64 `json:"dimensions,omitempty"` + MaxDeals int `json:"maxDeals,omitempty"` + Category []string `json:"c,omitempty"` + Segments []string `json:"segments,omitempty"` + Keywords []string `json:"keywords,omitempty"` + KeyValues map[string][]string `json:"kv,omitempty"` + AdUnitMatchingLabel []string `json:"auml,omitempty"` } type extDeviceAdnuntius struct { diff --git a/adapters/adnuntius/adnuntius_utils.go b/adapters/adnuntius/adnuntius_utils.go index ebbd7a8005..47e25bee6b 100644 --- a/adapters/adnuntius/adnuntius_utils.go +++ b/adapters/adnuntius/adnuntius_utils.go @@ -191,6 +191,27 @@ func generateAdUnit(imp openrtb2.Imp, adnuntiusExt openrtb_ext.ImpExtAdnunitus, if adnuntiusExt.MaxDeals > 0 { adUnit.MaxDeals = adnuntiusExt.MaxDeals } + + if adnuntiusExt.Targeting.Category != nil { + adUnit.Category = adnuntiusExt.Targeting.Category + } + + if adnuntiusExt.Targeting.Segments != nil { + adUnit.Segments = adnuntiusExt.Targeting.Segments + } + + if adnuntiusExt.Targeting.Keywords != nil { + adUnit.Keywords = adnuntiusExt.Targeting.Keywords + } + + if adnuntiusExt.Targeting.KeyValues != nil { + adUnit.KeyValues = adnuntiusExt.Targeting.KeyValues + } + + if adnuntiusExt.Targeting.AdUnitMatchingLabel != nil { + adUnit.AdUnitMatchingLabel = adnuntiusExt.Targeting.AdUnitMatchingLabel + } + return adUnit } diff --git a/adapters/adnuntius/adnuntiustest/supplemental/targeting-fields.json b/adapters/adnuntius/adnuntiustest/supplemental/targeting-fields.json new file mode 100644 index 0000000000..e626c2b3bb --- /dev/null +++ b/adapters/adnuntius/adnuntiustest/supplemental/targeting-fields.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "id": "1kjh3429kjh295jkl" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "auId": "123", + "targeting": { + "c": ["automotive", "tech"], + "segments": ["segment1", "segment2"], + "keywords": ["car", "tech", "mobile"], + "kv": { + "brand": ["toyota", "honda"], + "price": ["10000", "20000"] + }, + "auml": ["premium", "standard"] + } + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://whatever.url?format=prebidServer&tzo=0", + "body": { + "adUnits": [ + { + "auId": "123", + "targetId": "123-test-imp-id:banner", + "nativeRequest": {}, + "dimensions": [[300,250]], + "c": ["automotive", "tech"], + "segments": ["segment1", "segment2"], + "keywords": ["car", "tech", "mobile"], + "kv": { + "brand": ["toyota", "honda"], + "price": ["10000", "20000"] + }, + "auml": ["premium", "standard"] + } + ], + "metaData": { + "usi": "1kjh3429kjh295jkl" + }, + "context": "unknown" + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "adUnits": [ + { + "auId": "0000000000000123", + "targetId": "123-test-imp-id:banner", + "matchedAdCount": 1, + "html": "<ADCODE>", + "responseId": "adn-rsp-900646517", + "ads": [ + { + "destinationUrls": { + "url": "http://www.google.com" + }, + "advertiserDomains": ["google.com"], + "bid": { + "amount": 20.0, + "currency": "NOK" + }, + "adId": "adn-id-1559784094", + "creativeWidth": "300", + "creativeHeight": "250", + "creativeId": "jn9hpzvlsf8cpdmm", + "lineItemId": "q7y9qm5b0xt9htrv" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "adn-id-1559784094", + "impid": "test-imp-id", + "price": 20000, + "adm": "<ADCODE>", + "adid": "adn-id-1559784094", + "adomain": [ + "google.com" + ], + "cid": "q7y9qm5b0xt9htrv", + "crid": "jn9hpzvlsf8cpdmm", + "mtype": 1, + "w": 300, + "h": 250 + }, + "type": "banner" + } + ], + "currency": "NOK" + } + ] +} \ No newline at end of file diff --git a/openrtb_ext/imp_adnuntius.go b/openrtb_ext/imp_adnuntius.go index 49833e90f1..b73c9de061 100644 --- a/openrtb_ext/imp_adnuntius.go +++ b/openrtb_ext/imp_adnuntius.go @@ -2,8 +2,15 @@ package openrtb_ext type ImpExtAdnunitus struct { Auid string `json:"auId"` - Network string `json:"network"` NoCookies bool `json:"noCookies"` MaxDeals int `json:"maxDeals"` + Network string `json:"network"` BidType string `json:"bidType,omitempty"` + Targeting struct { + Category []string `json:"c,omitempty"` + Segments []string `json:"segments,omitempty"` + Keywords []string `json:"keywords,omitempty"` + KeyValues map[string][]string `json:"kv,omitempty"` + AdUnitMatchingLabel []string `json:"auml,omitempty"` + } `json:"targeting,omitempty"` } From 63abe48c63a4a954a2dd3d9a1a70327d0aa02e74 Mon Sep 17 00:00:00 2001 From: BoldwinDev <sdk@bold-win.com> Date: Tue, 11 Nov 2025 05:19:11 +0200 Subject: [PATCH 124/272] New Adapter: Boldwin Rapid (#4478) --- adapters/boldwin_rapid/boldwin_rapid.go | 172 ++++++ adapters/boldwin_rapid/boldwin_rapid_test.go | 530 ++++++++++++++++++ .../exemplary/banner-app.json | 170 ++++++ .../exemplary/native-app.json | 164 ++++++ .../exemplary/video-app.json | 178 ++++++ .../supplemental/bad_media_type.json | 88 +++ .../supplemental/bad_response.json | 86 +++ .../supplemental/status-204.json | 81 +++ .../supplemental/status-not-200.json | 86 +++ adapters/boldwin_rapid/params_test.go | 49 ++ exchange/adapter_builders.go | 2 + macros/macros.go | 1 + openrtb_ext/bidders.go | 2 + openrtb_ext/bidders_validate_test.go | 2 +- openrtb_ext/imp_boldwin_rapid.go | 6 + static/bidder-info/boldwin_rapid.yaml | 11 + static/bidder-params/boldwin_rapid.json | 20 + 17 files changed, 1647 insertions(+), 1 deletion(-) create mode 100644 adapters/boldwin_rapid/boldwin_rapid.go create mode 100644 adapters/boldwin_rapid/boldwin_rapid_test.go create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/exemplary/banner-app.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/exemplary/native-app.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/exemplary/video-app.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_media_type.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_response.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-204.json create mode 100644 adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-not-200.json create mode 100644 adapters/boldwin_rapid/params_test.go create mode 100644 openrtb_ext/imp_boldwin_rapid.go create mode 100644 static/bidder-info/boldwin_rapid.yaml create mode 100644 static/bidder-params/boldwin_rapid.json diff --git a/adapters/boldwin_rapid/boldwin_rapid.go b/adapters/boldwin_rapid/boldwin_rapid.go new file mode 100644 index 0000000000..1904cd8aca --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapid.go @@ -0,0 +1,172 @@ +package boldwin_rapid + +import ( + "encoding/json" + "fmt" + "text/template" + + "net/http" + + "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/macros" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint *template.Template +} + +func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) { + endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint template: %v", err) + } + + bidder := &adapter{ + endpoint: endpointTemplate, + } + + return bidder, nil +} + +func (a *adapter) buildEndpointURL(boldwinExt openrtb_ext.ImpExtBoldwinRapid) (string, error) { + endpointParams := macros.EndpointTemplateParams{ + PublisherID: boldwinExt.Pid, + PlacementID: boldwinExt.Tid, + } + + return macros.ResolveMacros(a.endpoint, endpointParams) +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var adapterRequests []*adapters.RequestData + + reqCopy := *request + headers := a.getHeaders(request) + + for _, imp := range request.Imp { + // Create a new request with just this impression + reqCopy.Imp = []openrtb2.Imp{imp} + + var bidderExt adapters.ExtImpBidder + var boldwinExt openrtb_ext.ImpExtBoldwinRapid + + // Use the current impression's Ext + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, []error{err} + } + + if err := jsonutil.Unmarshal(bidderExt.Bidder, &boldwinExt); err != nil { + return nil, []error{err} + } + + endpoint, err := a.buildEndpointURL(boldwinExt) + if err != nil { + return nil, []error{err} + } + + adapterReq, err := a.makeRequest(&reqCopy, endpoint, headers) + if err != nil { + return nil, []error{err} + } + + if adapterReq != nil { + adapterRequests = append(adapterRequests, adapterReq) + } + } + + return adapterRequests, nil +} + +func (a *adapter) getHeaders(request *openrtb2.BidRequest) http.Header { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("x-openrtb-version", "2.5") + headers.Add("Host", "rtb.beardfleet.com") // required header for the request + + if request.Device != nil { + if request.Device.UA != "" { + headers.Add("User-Agent", request.Device.UA) + } + + if len(request.Device.IPv6) > 0 { + headers.Set("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.IP) > 0 { + headers.Set("X-Forwarded-For", request.Device.IP) + headers.Add("IP", request.Device.IP) + } + } + + return headers +} + +func (a *adapter) makeRequest(request *openrtb2.BidRequest, endpoint string, headers http.Header) (*adapters.RequestData, error) { + reqJSON, err := json.Marshal(request) + if err != nil { + return nil, fmt.Errorf("failed to marshal request: %w", err) + } + + return &adapters.RequestData{ + Method: "POST", + Uri: endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + err := adapters.CheckResponseStatusCodeForErrors(responseData) + if err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, err := getBidMediaType(&seatBid.Bid[i]) + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getBidMediaType(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 + default: + return "", fmt.Errorf("Unable to fetch mediaType in multi-format: %s", bid.ImpID) + } +} diff --git a/adapters/boldwin_rapid/boldwin_rapid_test.go b/adapters/boldwin_rapid/boldwin_rapid_test.go new file mode 100644 index 0000000000..58e03ca2aa --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapid_test.go @@ -0,0 +1,530 @@ +package boldwin_rapid + +import ( + "encoding/json" + "errors" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "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/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderBoldwinRapid, config.Adapter{ + Endpoint: "https://rtb.beardfleet.com/auction/bid?pid={{.PublisherID}}&tid={{.PlacementID}}", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 1, + DataCenter: "2", + }, + ) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "boldwin_rapidtest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdhese, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} + +// TestMakeRequestsErrors tests error handling in the MakeRequests method +func TestMakeRequestsErrors(t *testing.T) { + testCases := []struct { + name string + givenBidRequest *openrtb2.BidRequest + mockAdapter *mockAdapter + expectedError string + }{ + { + name: "Error unmarshalling imp.Ext", + givenBidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`invalid json`), + }, + }, + }, + mockAdapter: &mockAdapter{}, + expectedError: "invalid character 'i' looking for beginning of value", + }, + { + name: "Error unmarshalling bidderExt.Bidder", + givenBidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": "invalid json"}`), + }, + }, + }, + mockAdapter: &mockAdapter{}, + expectedError: "json: cannot unmarshal string into Go value of type openrtb_ext.ImpExtBoldwinRapid", + }, + { + name: "Error building endpoint URL", + givenBidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"pid": "123", "tid": "456"}}`), + }, + }, + }, + mockAdapter: &mockAdapter{ + buildEndpointURLErr: errors.New("endpoint URL error"), + }, + expectedError: "endpoint URL error", + }, + { + name: "Error making request", + givenBidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"pid": "123", "tid": "456"}}`), + }, + }, + }, + mockAdapter: &mockAdapter{ + makeRequestErr: errors.New("make request error"), + }, + expectedError: "make request error", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // When + requests, errs := tc.mockAdapter.MakeRequests(tc.givenBidRequest, nil) + + // Then + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), tc.expectedError) + }) + } +} + +// Mock adapter for testing +type mockAdapter struct { + buildEndpointURLErr error + makeRequestErr error +} + +func (m *mockAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var adapterRequests []*adapters.RequestData + + reqCopy := *request + + for _, imp := range request.Imp { + // Create a new request with just this impression + reqCopy.Imp = []openrtb2.Imp{imp} + + var bidderExt adapters.ExtImpBidder + var boldwinExt openrtb_ext.ImpExtBoldwinRapid + + // Use the current impression's Ext + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, []error{err} + } + + if err := json.Unmarshal(bidderExt.Bidder, &boldwinExt); err != nil { + return nil, []error{err} + } + + if m.buildEndpointURLErr != nil { + return nil, []error{m.buildEndpointURLErr} + } + + if m.makeRequestErr != nil { + return nil, []error{m.makeRequestErr} + } + } + + return adapterRequests, nil +} + +func TestMakeRequestsUnmarshalErrors(t *testing.T) { + adapter, buildErr := Builder(openrtb_ext.BidderBoldwinRapid, config.Adapter{ + Endpoint: "https://rtb.beardfleet.com/auction/bid?pid={{.PublisherID}}&tid={{.PlacementID}}", + }, config.Server{}) + assert.NoError(t, buildErr) + + t.Run("invalid imp.Ext json", func(t *testing.T) { + bidRequest := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{invalid json}`), + }, + }, + } + + requests, errs := adapter.MakeRequests(bidRequest, nil) + assert.Nil(t, requests) + assert.Len(t, errs, 1) + assert.Error(t, errs[0]) + }) + + t.Run("invalid bidder extension json", func(t *testing.T) { + bidRequest := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {invalid json}}`), + }, + }, + } + + requests, errs := adapter.MakeRequests(bidRequest, nil) + assert.Nil(t, requests) + assert.Len(t, errs, 1) + assert.Error(t, errs[0]) + }) + + t.Run("bidder field is not valid json object", func(t *testing.T) { + bidRequest := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": "not an object"}`), + }, + }, + } + + requests, errs := adapter.MakeRequests(bidRequest, nil) + assert.Nil(t, requests) + assert.Len(t, errs, 1) + assert.Error(t, errs[0]) + }) +} + +func TestGetHeaders(t *testing.T) { + adapter := &adapter{} + + tests := []struct { + name string + requestJSON string + expectedHeader map[string]string + checkHeaders []string + }{ + { + name: "device with IP", + requestJSON: `{ + "device": { + "ip": "192.168.1.1" + } + }`, + expectedHeader: map[string]string{ + "X-Forwarded-For": "192.168.1.1", + "IP": "192.168.1.1", + }, + checkHeaders: []string{"X-Forwarded-For", "IP"}, + }, + { + name: "device with IPv6", + requestJSON: `{ + "device": { + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }`, + expectedHeader: map[string]string{ + "X-Forwarded-For": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + }, + checkHeaders: []string{"X-Forwarded-For"}, + }, + { + name: "device with both IP and IPv6", + requestJSON: `{ + "device": { + "ip": "192.168.1.1", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }`, + expectedHeader: map[string]string{ + "X-Forwarded-For": "192.168.1.1", + "IP": "192.168.1.1", + }, + checkHeaders: []string{"X-Forwarded-For", "IP"}, + }, + { + name: "device with User-Agent", + requestJSON: `{ + "device": { + "ua": "Mozilla/5.0" + } + }`, + expectedHeader: map[string]string{ + "User-Agent": "Mozilla/5.0", + }, + checkHeaders: []string{"User-Agent"}, + }, + { + name: "device with all fields", + requestJSON: `{ + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.1.1", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }`, + expectedHeader: map[string]string{ + "User-Agent": "Mozilla/5.0", + "X-Forwarded-For": "192.168.1.1", + "IP": "192.168.1.1", + }, + checkHeaders: []string{"User-Agent", "X-Forwarded-For", "IP"}, + }, + { + name: "no device", + requestJSON: `{}`, + expectedHeader: map[string]string{}, + checkHeaders: []string{}, + }, + { + name: "empty device fields", + requestJSON: `{ + "device": { + "ua": "", + "ip": "", + "ipv6": "" + } + }`, + expectedHeader: map[string]string{}, + checkHeaders: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var request openrtb2.BidRequest + err := json.Unmarshal([]byte(tt.requestJSON), &request) + assert.NoError(t, err) + + headers := adapter.getHeaders(&request) + + // Check required headers are always present + assert.Equal(t, "application/json;charset=utf-8", headers.Get("Content-Type")) + assert.Equal(t, "application/json", headers.Get("Accept")) + assert.Equal(t, "2.5", headers.Get("x-openrtb-version")) + assert.Equal(t, "rtb.beardfleet.com", headers.Get("Host")) + + // Check expected headers + for _, headerName := range tt.checkHeaders { + assert.Equal(t, tt.expectedHeader[headerName], headers.Get(headerName), "header %s mismatch", headerName) + } + + // Verify headers that should not be present when device fields are empty + if len(tt.checkHeaders) == 0 && request.Device != nil { + if request.Device.UA == "" { + assert.Empty(t, headers.Get("User-Agent")) + } + if len(request.Device.IP) == 0 && len(request.Device.IPv6) == 0 { + // X-Forwarded-For should only have one value or none + assert.True(t, headers.Get("X-Forwarded-For") == "" || len(headers.Values("X-Forwarded-For")) <= 1) + } + } + }) + } +} + +func TestMakeBids(t *testing.T) { + adapter := &adapter{} + + t.Run("no content response", func(t *testing.T) { + responseData := &adapters.ResponseData{ + StatusCode: 204, + } + + bidderResp, errs := adapter.MakeBids(nil, nil, responseData) + assert.Nil(t, bidderResp) + assert.Nil(t, errs) + }) + + t.Run("error status code", func(t *testing.T) { + responseData := &adapters.ResponseData{ + StatusCode: 500, + Body: []byte("Internal Server Error"), + } + + bidderResp, errs := adapter.MakeBids(nil, nil, responseData) + assert.Nil(t, bidderResp) + assert.Len(t, errs, 1) + }) + + t.Run("invalid response body json", func(t *testing.T) { + responseData := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(`{invalid json}`), + } + + bidderResp, errs := adapter.MakeBids(nil, nil, responseData) + assert.Nil(t, bidderResp) + assert.Len(t, errs, 1) + assert.Error(t, errs[0]) + }) + + t.Run("successful response with currency", func(t *testing.T) { + responseJSON := `{ + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.5, + "mtype": 1 + } + ] + } + ] + }` + + responseData := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "imp1"}}, + } + + bidderResp, errs := adapter.MakeBids(request, nil, responseData) + assert.Nil(t, errs) + assert.NotNil(t, bidderResp) + assert.Equal(t, "USD", bidderResp.Currency) + assert.Len(t, bidderResp.Bids, 1) + assert.Equal(t, openrtb_ext.BidTypeBanner, bidderResp.Bids[0].BidType) + }) + + t.Run("multiple bids with different types", func(t *testing.T) { + responseJSON := `{ + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.5, + "mtype": 1 + }, + { + "id": "bid2", + "impid": "imp2", + "price": 2.0, + "mtype": 2 + }, + { + "id": "bid3", + "impid": "imp3", + "price": 3.0, + "mtype": 4 + } + ] + } + ] + }` + + responseData := &adapters.ResponseData{ + StatusCode: 200, + Body: []byte(responseJSON), + } + + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + {ID: "imp1"}, + {ID: "imp2"}, + {ID: "imp3"}, + }, + } + + bidderResp, errs := adapter.MakeBids(request, nil, responseData) + assert.Nil(t, errs) + assert.NotNil(t, bidderResp) + assert.Len(t, bidderResp.Bids, 3) + assert.Equal(t, openrtb_ext.BidTypeBanner, bidderResp.Bids[0].BidType) + assert.Equal(t, openrtb_ext.BidTypeVideo, bidderResp.Bids[1].BidType) + assert.Equal(t, openrtb_ext.BidTypeNative, bidderResp.Bids[2].BidType) + }) +} + +func TestGetBidMediaType(t *testing.T) { + t.Run("banner type", func(t *testing.T) { + bid := &openrtb2.Bid{ + ImpID: "imp1", + MType: openrtb2.MarkupBanner, + } + + bidType, err := getBidMediaType(bid) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeBanner, bidType) + }) + + t.Run("video type", func(t *testing.T) { + bid := &openrtb2.Bid{ + ImpID: "imp1", + MType: openrtb2.MarkupVideo, + } + + bidType, err := getBidMediaType(bid) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeVideo, bidType) + }) + + t.Run("native type", func(t *testing.T) { + bid := &openrtb2.Bid{ + ImpID: "imp1", + MType: openrtb2.MarkupNative, + } + + bidType, err := getBidMediaType(bid) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeNative, bidType) + }) +} + +func TestMakeRequestsMultipleImpressions(t *testing.T) { + adapter, err := Builder(openrtb_ext.BidderBoldwinRapid, config.Adapter{ + Endpoint: "https://rtb.beardfleet.com/auction/bid?pid={{.PublisherID}}&tid={{.PlacementID}}", + }, config.Server{}) + require.NoError(t, err) + + t.Run("multiple impressions create multiple requests", func(t *testing.T) { + bidRequest := &openrtb2.BidRequest{ + ID: "test-request", + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Ext: json.RawMessage(`{"bidder": {"pid": "pub1", "tid": "tag1"}}`), + }, + { + ID: "imp2", + Ext: json.RawMessage(`{"bidder": {"pid": "pub2", "tid": "tag2"}}`), + }, + }, + } + + requests, errs := adapter.MakeRequests(bidRequest, nil) + assert.Nil(t, errs) + assert.Len(t, requests, 2) + assert.Contains(t, requests[0].Uri, "pid=pub1&tid=tag1") + assert.Contains(t, requests[1].Uri, "pid=pub2&tid=tag2") + }) +} diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/banner-app.json b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/banner-app.json new file mode 100644 index 0000000000..bff277f063 --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/banner-app.json @@ -0,0 +1,170 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "Host": [ + "rtb.beardfleet.com" + ], + "Ip": [ + "123.123.123.123" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "seat": "boldwin_rapid" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "boldwin_rapid": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/native-app.json b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/native-app.json new file mode 100644 index 0000000000..1c3b700a80 --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/native-app.json @@ -0,0 +1,164 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "Host": [ + "rtb.beardfleet.com" + ], + "Ip": [ + "123.123.123.123" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + }, + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": ["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "mtype": 4 + } + ], + "seat": "boldwin_rapid" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "boldwin_rapid": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/video-app.json b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/video-app.json new file mode 100644 index 0000000000..d57cd46073 --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/exemplary/video-app.json @@ -0,0 +1,178 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "Host": [ + "rtb.beardfleet.com" + ], + "Ip": [ + "123.123.123.123" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": ["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 1280, + "h": 720, + "mtype": 2 + } + ], + "seat": "boldwin_rapid" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "boldwin_rapid": 154 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 1280, + "h": 720, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_media_type.json b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_media_type.json new file mode 100644 index 0000000000..3b90946f47 --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_media_type.json @@ -0,0 +1,88 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://rtb.beardfleet.com/auction/bid?k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "boldwin_rapid" + } + ], + "cur": "USD" + } + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unable to fetch mediaType in multi-format: test-imp-id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_response.json b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_response.json new file mode 100644 index 0000000000..2483e5bfdf --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/bad_response.json @@ -0,0 +1,86 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + }], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-204.json b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-204.json new file mode 100644 index 0000000000..f85bd2fbb3 --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-204.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-not-200.json b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-not-200.json new file mode 100644 index 0000000000..659cfe699c --- /dev/null +++ b/adapters/boldwin_rapid/boldwin_rapidtest/supplemental/status-not-200.json @@ -0,0 +1,86 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://rtb.beardfleet.com/auction/bid?pid=publisher123&tid=placement123", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "pid": "publisher123", + "tid": "placement123" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 404, + "body": {} + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/boldwin_rapid/params_test.go b/adapters/boldwin_rapid/params_test.go new file mode 100644 index 0000000000..d43843271a --- /dev/null +++ b/adapters/boldwin_rapid/params_test.go @@ -0,0 +1,49 @@ +package boldwin_rapid + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderBoldwinRapid, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderBoldwin, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"pid": "1234", "tid": "967e42a4435b2ced033cc938"}`, +} + +var invalidParams = []string{ + `null`, + `nil`, + ``, + `[]`, + `true`, + `{"pid": "1234"}`, + `{"pid": 42}`, + `{"pid": "qwertyui", "tid": 456789}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index aa578b089f..fa3f6d8370 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -71,6 +71,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/bluesea" "github.com/prebid/prebid-server/v3/adapters/bmtm" "github.com/prebid/prebid-server/v3/adapters/boldwin" + "github.com/prebid/prebid-server/v3/adapters/boldwin_rapid" "github.com/prebid/prebid-server/v3/adapters/brave" "github.com/prebid/prebid-server/v3/adapters/bwx" cadentaperturemx "github.com/prebid/prebid-server/v3/adapters/cadent_aperture_mx" @@ -338,6 +339,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBluesea: bluesea.Builder, openrtb_ext.BidderBmtm: bmtm.Builder, openrtb_ext.BidderBoldwin: boldwin.Builder, + openrtb_ext.BidderBoldwinRapid: boldwin_rapid.Builder, openrtb_ext.BidderBrave: brave.Builder, openrtb_ext.BidderBWX: bwx.Builder, openrtb_ext.BidderCadentApertureMX: cadentaperturemx.Builder, diff --git a/macros/macros.go b/macros/macros.go index 1fff558b39..f24974b572 100644 --- a/macros/macros.go +++ b/macros/macros.go @@ -22,6 +22,7 @@ type EndpointTemplateParams struct { SspID string SeatID string TokenID string + PlacementID string } // UserSyncPrivacy specifies privacy policy macros, represented as strings, for user sync urls. diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 4469ed3f2f..d9df5e8909 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -87,6 +87,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderBluesea, BidderBmtm, BidderBoldwin, + BidderBoldwinRapid, BidderBrave, BidderBWX, BidderCadentApertureMX, @@ -461,6 +462,7 @@ const ( BidderBluesea BidderName = "bluesea" BidderBmtm BidderName = "bmtm" BidderBoldwin BidderName = "boldwin" + BidderBoldwinRapid BidderName = "boldwin_rapid" BidderBrave BidderName = "brave" BidderBWX BidderName = "bwx" BidderCadentApertureMX BidderName = "cadent_aperture_mx" diff --git a/openrtb_ext/bidders_validate_test.go b/openrtb_ext/bidders_validate_test.go index 66de818311..ed30eaea39 100644 --- a/openrtb_ext/bidders_validate_test.go +++ b/openrtb_ext/bidders_validate_test.go @@ -50,7 +50,7 @@ func TestBidderUniquenessGatekeeping(t *testing.T) { // - Exclude duplicates of adapters for the same bidder, as it's unlikely a publisher will use both. var bidders []string for _, bidder := range CoreBidderNames() { - if bidder != BidderSilverPush && bidder != BidderTripleliftNative && bidder != BidderAdkernelAdn && bidder != "freewheel-ssp" && bidder != "yahooAdvertising" { + if bidder != BidderSilverPush && bidder != BidderTripleliftNative && bidder != BidderAdkernelAdn && bidder != "freewheel-ssp" && bidder != "yahooAdvertising" && bidder != "boldwin_rapid" { bidders = append(bidders, string(bidder)) } } diff --git a/openrtb_ext/imp_boldwin_rapid.go b/openrtb_ext/imp_boldwin_rapid.go new file mode 100644 index 0000000000..53fb59d4d5 --- /dev/null +++ b/openrtb_ext/imp_boldwin_rapid.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtBoldwinRapid struct { + Pid string `json:"pid"` + Tid string `json:"tid"` +} diff --git a/static/bidder-info/boldwin_rapid.yaml b/static/bidder-info/boldwin_rapid.yaml new file mode 100644 index 0000000000..4ab3e062cc --- /dev/null +++ b/static/bidder-info/boldwin_rapid.yaml @@ -0,0 +1,11 @@ +endpoint: "https://rtb.beardfleet.com/auction/bid?pid={{.PublisherID}}&tid={{.PlacementID}}" +maintainer: + email: "info@bold-win.com" +openrtb: + version: 2.5 +capabilities: + app: + mediaTypes: + - banner + - video + - native \ No newline at end of file diff --git a/static/bidder-params/boldwin_rapid.json b/static/bidder-params/boldwin_rapid.json new file mode 100644 index 0000000000..3ace36456c --- /dev/null +++ b/static/bidder-params/boldwin_rapid.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Boldwin-Rapid Adapter Params", + "description": "A schema which validates params accepted by the Boldwin-rapid adapter", + "type": "object", + + "properties": { + "pid": { + "type": "string", + "minLength": 1, + "description": "Publisher ID" + }, + "tid": { + "type": "string", + "minLength": 1, + "description": "Placement ID" + } + }, + "required": ["pid", "tid"] +} \ No newline at end of file From 30c7364765e44372d45581ea3ebd4959b8bd7b9c Mon Sep 17 00:00:00 2001 From: Gabriel Gravel <gravelg@users.noreply.github.com> Date: Mon, 10 Nov 2025 22:42:38 -0500 Subject: [PATCH 125/272] Scope3: Various fixes to RTD module (#4544) --- modules/scope3/rtd/README.md | 10 ++++----- modules/scope3/rtd/module.go | 34 +++++++++++++++++++++++++++---- modules/scope3/rtd/module_test.go | 18 ++++++++-------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/modules/scope3/rtd/README.md b/modules/scope3/rtd/README.md index 734874b0bc..3db4d447e2 100644 --- a/modules/scope3/rtd/README.md +++ b/modules/scope3/rtd/README.md @@ -17,7 +17,7 @@ hooks: rtd: enabled: true auth_key: ${SCOPE3_API_KEY} # Set SCOPE3_API_KEY environment variable - endpoint: https://rtdp.scope3.com/amazonaps/rtii + endpoint: https://rtdp.scope3.com/prebid/prebid timeout_ms: 1000 cache_ttl_seconds: 60 # Cache segments for 60 seconds (default) add_to_targeting: false # Set to true to add segments as individual targeting keys for GAM @@ -25,7 +25,7 @@ hooks: enabled: true # Enable field masking before sending to Scope3 geo: preserve_metro: true # Preserve DMA code (default: true) - preserve_zip: true # Preserve postal code (default: true) + preserve_zip: true # Preserve postal code (default: true) preserve_city: false # Preserve city name (default: false) lat_long_precision: 2 # Lat/long decimal places: 0-4 (default: 2) user: @@ -68,7 +68,7 @@ hooks: "scope3": { "rtd": { "enabled": true, - "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "endpoint": "https://rtdp.scope3.com/prebid/prebid", "auth_key": "your-scope3-auth-key", "timeout_ms": 1000, "cache_ttl_seconds": 60, @@ -238,7 +238,7 @@ masking: **GDPR Compliance** - Removes direct identifiers by default -- Configurable to meet legitimate interest requirements +- Configurable to meet legitimate interest requirements - Supports privacy-by-design principles **CCPA Compliance** @@ -297,7 +297,7 @@ This module automatically detects and forwards available user identifiers from t - Other standard OpenRTB identifiers ### How It Works -The module forwards the complete bid request with all available user identifiers to the Scope3 API. Scope3's system can then utilize whatever identifiers are available for audience segmentation, whether they are resolved identifiers or encrypted envelopes that Scope3 may be able to process. +The module forwards any fields that are not masked from the bid request to the Scope3 API (please see the [Privacy Protection](#privacy-protection) section for more details). Scope3's system can then utilize whatever identifiers are available for audience segmentation, whether they are resolved identifiers or encrypted envelopes that Scope3 may be able to process. **Note**: The effectiveness of different identifier types depends on Scope3's integration capabilities and partnerships. diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go index ce1bd48fd1..e4c19380b2 100644 --- a/modules/scope3/rtd/module.go +++ b/modules/scope3/rtd/module.go @@ -37,7 +37,7 @@ func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, e } if cfg.Endpoint == "" { - cfg.Endpoint = "https://rtdp.scope3.com/prebid/rtii" + cfg.Endpoint = DefaultScope3RTDURL } if cfg.Timeout == 0 { cfg.Timeout = 1000 // 1000ms default @@ -45,6 +45,9 @@ func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, e if cfg.CacheTTL == 0 { cfg.CacheTTL = 60 // 60 seconds default } + if cfg.CacheSize == 0 { + cfg.CacheSize = 10 * 1024 * 1024 // 10MB + } // Set masking defaults and validate configuration if cfg.Masking.Enabled { @@ -76,7 +79,7 @@ func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, e Timeout: time.Duration(cfg.Timeout) * time.Millisecond, Transport: deps.HTTPClient.Transport, }, - cache: freecache.NewCache(10 * 1024 * 1024), + cache: freecache.NewCache(cfg.CacheSize), sha256Pool: &sync.Pool{ New: func() any { return sha256.New() @@ -87,9 +90,15 @@ func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, e const ( // keys for miCtx - asyncRequestKey = "scope3.AsyncRequest" + asyncRequestKey = "scope3.AsyncRequest" + scope3MacroKey = "scope3_macro" + scope3MacroSeparator = ";" ) +var scope3MacroKeyPlusSeparator = scope3MacroKey + scope3MacroSeparator + +const DefaultScope3RTDURL = "https://rtdp.scope3.com/prebid/prebid" + var ( // Declare hooks _ hookstage.Entrypoint = (*Module)(nil) @@ -103,6 +112,7 @@ type Config struct { AuthKey string `json:"auth_key"` Timeout int `json:"timeout_ms"` CacheTTL int `json:"cache_ttl_seconds"` // Cache segments for this many seconds + CacheSize int `json:"cache_size"` // Maximum size of segment cache in bytes AddToTargeting bool `json:"add_to_targeting"` // Add segments as individual targeting keys Masking MaskingConfig `json:"masking"` // Privacy masking configuration } @@ -162,6 +172,7 @@ type Scope3Ext struct { type Scope3ExtData struct { Segments []Scope3Segment `json:"segments"` + Macro string `json:"macro"` } type Scope3Segment struct { @@ -326,7 +337,15 @@ func (m *Module) HandleAuctionResponseHook( } // Add each segment as individual targeting key for _, segment := range segments { - targetingMap[segment] = "true" + if strings.HasPrefix(segment, scope3MacroKeyPlusSeparator) { + macroKeyVal := strings.Split(segment, scope3MacroSeparator) + if len(macroKeyVal) != 2 { + continue + } + targetingMap[macroKeyVal[0]] = macroKeyVal[1] + } else { + targetingMap[segment] = "true" + } } } @@ -404,10 +423,14 @@ func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.B // Extract unique segments (exclude destination) segmentMap := make(map[string]bool) + var macro string for data := range iterutil.SlicePointerValues(scope3Resp.Data) { // Extract actual segments from impression-level data for imp := range iterutil.SlicePointerValues(data.Imp) { if imp.Ext != nil && imp.Ext.Scope3 != nil { + if imp.Ext.Scope3.Macro != "" { + macro = imp.Ext.Scope3.Macro + } for segment := range iterutil.SlicePointerValues(imp.Ext.Scope3.Segments) { segmentMap[segment.ID] = true } @@ -417,6 +440,9 @@ func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.B // Convert to slice segments := slices.AppendSeq(make([]string, 0, len(segmentMap)), maps.Keys(segmentMap)) + if macro != "" { + segments = append(segments, scope3MacroKeyPlusSeparator+macro) + } // Cache the result err = m.cache.Set(cacheKey, []byte(strings.Join(segments, ",")), m.cfg.CacheTTL) diff --git a/modules/scope3/rtd/module_test.go b/modules/scope3/rtd/module_test.go index 47638a01bc..8b46d3bbb8 100644 --- a/modules/scope3/rtd/module_test.go +++ b/modules/scope3/rtd/module_test.go @@ -40,7 +40,7 @@ func getTestEntrypointPayload(t *testing.T) hookstage.EntrypointPayload { func TestBuilder(t *testing.T) { config := json.RawMessage(`{ "enabled": true, - "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "endpoint": "` + DefaultScope3RTDURL + `", "auth_key": "test-key", "timeout_ms": 1000, "cache_ttl_seconds": 60, @@ -55,7 +55,7 @@ func TestBuilder(t *testing.T) { assert.IsType(t, &Module{}, module) m := module.(*Module) - assert.Equal(t, "https://rtdp.scope3.com/amazonaps/rtii", m.cfg.Endpoint) + assert.Equal(t, DefaultScope3RTDURL, m.cfg.Endpoint) assert.Equal(t, "test-key", m.cfg.AuthKey) assert.Equal(t, 1000, m.cfg.Timeout) assert.Equal(t, 60, m.cfg.CacheTTL) @@ -112,7 +112,7 @@ func TestBuilderDefaults(t *testing.T) { assert.NoError(t, err) m := module.(*Module) - assert.Equal(t, "https://rtdp.scope3.com/prebid/rtii", m.cfg.Endpoint) + assert.Equal(t, DefaultScope3RTDURL, m.cfg.Endpoint) assert.Equal(t, 1000, m.cfg.Timeout) assert.Equal(t, 60, m.cfg.CacheTTL) assert.Equal(t, false, m.cfg.AddToTargeting) @@ -136,6 +136,7 @@ func TestScope3APIIntegration(t *testing.T) { "id": "test-imp-1", "ext": { "scope3": { + "macro": "test-macro", "segments": [ {"id": "gmp_eligible"}, {"id": "gmp_plus_eligible"} @@ -196,9 +197,8 @@ func TestScope3APIIntegration(t *testing.T) { ctx := context.Background() segments, err := module.fetchScope3Segments(ctx, bidRequest) require.NoError(t, err) - assert.Len(t, segments, 2) - assert.Contains(t, segments, "gmp_eligible") - assert.Contains(t, segments, "gmp_plus_eligible") + assert.Len(t, segments, 3) + assert.ElementsMatch(t, segments, []string{"gmp_eligible", "gmp_plus_eligible", "scope3_macro;test-macro"}) assert.NotContains(t, segments, "triplelift.com") // Should not include destination } @@ -214,6 +214,7 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { "id": "test-imp-1", "ext": { "scope3": { + "macro": "test-macro", "segments": [ {"id": "test_segment_1"}, {"id": "test_segment_2"} @@ -306,7 +307,7 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { require.True(t, exists) segments, exists := scope3Data["segments"].([]interface{}) require.True(t, exists) - assert.Len(t, segments, 2) + assert.Len(t, segments, 3) // Verify targeting section exists (add_to_targeting: true) prebidData, exists := extMap["prebid"].(map[string]interface{}) @@ -317,6 +318,7 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { // Check individual targeting keys assert.Equal(t, "true", targetingData["test_segment_1"]) assert.Equal(t, "true", targetingData["test_segment_2"]) + assert.Equal(t, "test-macro", targetingData["scope3_macro"]) } func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { @@ -591,7 +593,7 @@ func TestScope3APIError(t *testing.T) { func TestBuilderWithMasking(t *testing.T) { config := json.RawMessage(`{ "enabled": true, - "endpoint": "https://rtdp.scope3.com/amazonaps/rtii", + "endpoint": "https://rtdp.scope3.com/prebid/prebid", "auth_key": "test-key", "timeout_ms": 1000, "cache_ttl_seconds": 60, From cef3959d550af5ccb3b51b91daab967d2a100cf2 Mon Sep 17 00:00:00 2001 From: Pubmatic-Supriya-Patil <131644110+Pubmatic-Supriya-Patil@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:19:07 +0530 Subject: [PATCH 126/272] PubMatic: Pass alias bidder name through (#4588) --- adapters/pubmatic/pubmatic.go | 20 +- adapters/pubmatic/pubmatic_test.go | 34 +++- .../pubmatictest/exemplary/banner.json | 3 +- .../pubmatictest/exemplary/native.json | 3 +- .../pubmatictest/exemplary/video.json | 3 +- .../supplemental/bid_ext_ibv_true.json | 3 +- .../pubmatictest/supplemental/extra-bid.json | 3 +- .../supplemental/native_invalid_adm.json | 3 +- .../pubmatictest/supplemental/nilReqExt.json | 3 +- .../supplemental/reqBidderParams.json | 3 +- .../supplemental/reqExtPrebidAliases.json | 176 ++++++++++++++++++ exchange/exchangetest/aliases.json | 9 +- .../exchangetest/bidadjustmentfactors.json | 9 +- .../buyeruid_case_insensitive.json | 18 +- .../eidpermissions-allowed-alias.json | 9 +- exchange/exchangetest/tricky-userids.json | 9 +- exchange/utils.go | 8 + exchange/utils_test.go | 5 + 18 files changed, 300 insertions(+), 21 deletions(-) create mode 100644 adapters/pubmatic/pubmatictest/supplemental/reqExtPrebidAliases.json diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index 7c112670cb..e35229143c 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -24,6 +24,8 @@ const MAX_IMPRESSIONS_PUBMATIC = 30 const ae = "ae" +const BidderPubMatic = "pubmatic" + type PubmaticAdapter struct { URI string bidderName string @@ -37,8 +39,9 @@ type pubmaticBidExt struct { } type pubmaticWrapperExt struct { - ProfileID int `json:"profile,omitempty"` - VersionID int `json:"version,omitempty"` + ProfileID int `json:"profile,omitempty"` + VersionID int `json:"version,omitempty"` + BidderCode string `json:"biddercode,omitempty"` } type pubmaticBidExtVideo struct { @@ -386,6 +389,19 @@ func extractPubmaticExtFromRequest(request *openrtb2.BidRequest) (extRequestAdSe pmReqExt.Wrapper = wrpExt } + if pmReqExt.Wrapper == nil { + pmReqExt.Wrapper = &pubmaticWrapperExt{} + } + + // Always set bidder code to default + pmReqExt.Wrapper.BidderCode = BidderPubMatic + + // Override bidder code if alias exists + for alias := range reqExt.Prebid.Aliases { + pmReqExt.Wrapper.BidderCode = alias + break + } + if acatBytes, ok := reqExtBidderParams["acat"]; ok { var acat []string err = jsonutil.Unmarshal(acatBytes, &acat) diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go index d26754c8c6..ac1e645c19 100644 --- a/adapters/pubmatic/pubmatic_test.go +++ b/adapters/pubmatic/pubmatic_test.go @@ -285,7 +285,7 @@ func TestExtractPubmaticExtFromRequest(t *testing.T) { Ext: json.RawMessage(`{"prebid":{"bidderparams":{}}}`), }, }, - expectedReqExt: extRequestAdServer{}, + expectedReqExt: extRequestAdServer{Wrapper: &pubmaticWrapperExt{ProfileID: 0, VersionID: 0, BidderCode: "pubmatic"}}, wantErr: false, }, { @@ -296,7 +296,7 @@ func TestExtractPubmaticExtFromRequest(t *testing.T) { }, }, expectedReqExt: extRequestAdServer{ - Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456}, + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic"}, }, wantErr: false, }, @@ -317,7 +317,7 @@ func TestExtractPubmaticExtFromRequest(t *testing.T) { }, }, expectedReqExt: extRequestAdServer{ - Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456}, + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic"}, Acat: []string{"drg", "dlu", "ssr"}, }, wantErr: false, @@ -330,7 +330,7 @@ func TestExtractPubmaticExtFromRequest(t *testing.T) { }, }, expectedReqExt: extRequestAdServer{ - Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456}, + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic"}, }, wantErr: true, }, @@ -343,7 +343,31 @@ func TestExtractPubmaticExtFromRequest(t *testing.T) { }, expectedReqExt: extRequestAdServer{ Marketplace: &marketplaceReqExt{AllowedBidders: []string{"pubmatic", "groupm"}}, - Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456}, + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic"}, + }, + wantErr: false, + }, + { + name: "Valid_request_ext_with_alias", + args: args{ + request: &openrtb2.BidRequest{ + Ext: json.RawMessage(`{"prebid":{"aliases":{"pubmatic-1":"pubmatic"},"bidderparams":{"wrapper":{"profile":123,"version":456}}}}`), + }, + }, + expectedReqExt: extRequestAdServer{ + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic-1"}, + }, + wantErr: false, + }, + { + name: "Valid_request_ext_with_empty_alias", + args: args{ + request: &openrtb2.BidRequest{ + Ext: json.RawMessage(`{"prebid":{"aliases":{},"bidderparams":{"wrapper":{"profile":123,"version":456}}}}`), + }, + }, + expectedReqExt: extRequestAdServer{ + Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456, BidderCode: "pubmatic"}, }, wantErr: false, }, diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json index af6c70f112..f371349dc0 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/banner.json +++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json @@ -86,7 +86,8 @@ "ext": { "wrapper": { "profile": 5123, - "version":1 + "version":1, + "biddercode":"pubmatic" }, "acat": ["drg","dlu","ssr"] } diff --git a/adapters/pubmatic/pubmatictest/exemplary/native.json b/adapters/pubmatic/pubmatictest/exemplary/native.json index e154ae995e..e054a10a4e 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/native.json +++ b/adapters/pubmatic/pubmatictest/exemplary/native.json @@ -55,7 +55,8 @@ "ext": { "wrapper": { "profile": 5123, - "version": 1 + "version": 1, + "biddercode":"pubmatic" } } }, diff --git a/adapters/pubmatic/pubmatictest/exemplary/video.json b/adapters/pubmatic/pubmatictest/exemplary/video.json index c92c97dd31..a3e4ec22f0 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/video.json +++ b/adapters/pubmatic/pubmatictest/exemplary/video.json @@ -97,7 +97,8 @@ "ext": { "wrapper": { "profile": 5123, - "version":1 + "version":1, + "biddercode":"pubmatic" }, "acat": ["drg","dlu","ssr"] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json b/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json index b994a00800..f4d3cc7b76 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json +++ b/adapters/pubmatic/pubmatictest/supplemental/bid_ext_ibv_true.json @@ -97,7 +97,8 @@ "ext": { "wrapper": { "profile": 5123, - "version":1 + "version":1, + "biddercode":"pubmatic" }, "acat": ["drg","dlu","ssr"] } diff --git a/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json b/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json index b6f2b53ec1..3cdb3b7f0c 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json +++ b/adapters/pubmatic/pubmatictest/supplemental/extra-bid.json @@ -97,7 +97,8 @@ "ext": { "wrapper": { "profile": 5123, - "version":1 + "version":1, + "biddercode":"pubmatic" }, "acat": ["drg","dlu","ssr"], "marketplace": { diff --git a/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json b/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json index 052409415a..a28a470970 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json +++ b/adapters/pubmatic/pubmatictest/supplemental/native_invalid_adm.json @@ -55,7 +55,8 @@ "ext": { "wrapper": { "profile": 5123, - "version": 1 + "version": 1, + "biddercode":"pubmatic" } } }, diff --git a/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json b/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json index e5a119f9cb..ea7a62b79f 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json +++ b/adapters/pubmatic/pubmatictest/supplemental/nilReqExt.json @@ -89,7 +89,8 @@ "ext": { "wrapper": { "profile": 5123, - "version": 1 + "version": 1, + "biddercode":"pubmatic" } } }, diff --git a/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json b/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json index cc1cc136a7..dbc0ae5cff 100644 --- a/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json +++ b/adapters/pubmatic/pubmatictest/supplemental/reqBidderParams.json @@ -98,7 +98,8 @@ "ext": { "wrapper": { "profile": 1234, - "version": 2 + "version": 2, + "biddercode":"pubmatic" } } }, diff --git a/adapters/pubmatic/pubmatictest/supplemental/reqExtPrebidAliases.json b/adapters/pubmatic/pubmatictest/supplemental/reqExtPrebidAliases.json new file mode 100644 index 0000000000..96787f0d39 --- /dev/null +++ b/adapters/pubmatic/pubmatictest/supplemental/reqExtPrebidAliases.json @@ -0,0 +1,176 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "adSlot": "AdTag_Div1@300x250", + "publisherId": " 999 ", + "keywords": [ + { + "key": "pmZoneID", + "value": [ + "Zone1", + "Zone2" + ] + }, + { + "key": "preference", + "value": [ + "sports", + "movies" + ] + } + ], + "wrapper": { + "version": 1, + "profile": 5123 + } + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "ext": { + "prebid": { + "aliases": { + "pubmatic-alias": "pubmatic" + }, + "bidderparams": { + "wrapper": { + "profile": 1234, + "version": 2 + } + } + } + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://hbopenbid.pubmatic.com/translator?source=prebid-server", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "AdTag_Div1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "h": 250, + "w": 300 + }, + "ext": { + "pmZoneId": "Zone1,Zone2", + "preference": "sports,movies" + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "999" + } + }, + "ext": { + "wrapper": { + "profile": 1234, + "version": 2, + "biddercode": "pubmatic-alias" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "958", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "h": 250, + "w": 300, + "dealid": "test deal", + "mtype": 1, + "ext": { + "dspid": 6, + "deal_channel": 1 + } + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "pubmatic.com" + ], + "crid": "29681110", + "w": 300, + "h": 250, + "dealid": "test deal", + "mtype": 1, + "ext": { + "dspid": 6, + "deal_channel": 1 + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/exchange/exchangetest/aliases.json b/exchange/exchangetest/aliases.json index 239e80b59e..5b27e6c756 100644 --- a/exchange/exchangetest/aliases.json +++ b/exchange/exchangetest/aliases.json @@ -97,7 +97,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "districtm": "appnexus" + } + } + } } }, "mockResponse": { diff --git a/exchange/exchangetest/bidadjustmentfactors.json b/exchange/exchangetest/bidadjustmentfactors.json index 84e0148ba8..0281906547 100644 --- a/exchange/exchangetest/bidadjustmentfactors.json +++ b/exchange/exchangetest/bidadjustmentfactors.json @@ -96,7 +96,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "districtm": "appnexus" + } + } + } }, "bidAdjustments": { "appnexus": 2.5, diff --git a/exchange/exchangetest/buyeruid_case_insensitive.json b/exchange/exchangetest/buyeruid_case_insensitive.json index 6999e8c951..a080fdb3c7 100644 --- a/exchange/exchangetest/buyeruid_case_insensitive.json +++ b/exchange/exchangetest/buyeruid_case_insensitive.json @@ -74,7 +74,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "APPnexus": "appnexus" + } + } + } } } }, @@ -103,7 +110,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "appNEXUS": "appnexus" + } + } + } } } }, diff --git a/exchange/exchangetest/eidpermissions-allowed-alias.json b/exchange/exchangetest/eidpermissions-allowed-alias.json index 886927723c..2dee83fb58 100644 --- a/exchange/exchangetest/eidpermissions-allowed-alias.json +++ b/exchange/exchangetest/eidpermissions-allowed-alias.json @@ -93,7 +93,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "foo": "appnexus" + } + } + } } }, "mockResponse": { diff --git a/exchange/exchangetest/tricky-userids.json b/exchange/exchangetest/tricky-userids.json index 180415db26..087b2e71a5 100644 --- a/exchange/exchangetest/tricky-userids.json +++ b/exchange/exchangetest/tricky-userids.json @@ -147,7 +147,14 @@ } } } - ] + ], + "ext": { + "prebid": { + "aliases": { + "districtm": "appnexus" + } + } + } } }, "mockResponse": { diff --git a/exchange/utils.go b/exchange/utils.go index 3b88f3d860..9659f19570 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -506,6 +506,14 @@ func buildRequestExtForBidder(bidder string, req *openrtb_ext.RequestWrapper, re AlternateBidderCodes: alternateBidderCodes, } + if prebid != nil && prebid.Aliases != nil { + if aliasValue, ok := prebid.Aliases[bidder]; ok { + prebidNew.Aliases = map[string]string{ + bidder: aliasValue, + } + } + } + // Copy Allowed Fields // Per: https://docs.prebid.org/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#prebid-server-ortb2-extension-summary if prebid != nil { diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 1d1a5c2ac4..317d7a640c 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -2752,6 +2752,11 @@ func TestBuildRequestExtForBidder(t *testing.T) { requestExt: json.RawMessage(`{"prebid":{"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includebidderkeys":true,"includewinners":true,"includebrandcategory":{"primaryadserver":1,"publisher":"anyPublisher","withcategory":true}}}}`), expectedJson: json.RawMessage(`{"prebid":{"targeting":{"includebrandcategory":{"primaryadserver":1,"publisher":"anyPublisher","withcategory":true}}}}`), }, + { + name: "request_ext_with_aliase", + requestExt: json.RawMessage(`{"prebid":{"aliases":{"foo":"pubmatic", "bar":"pubmatic"}}}`), + expectedJson: json.RawMessage(`{"prebid":{"aliases":{"foo":"pubmatic"}}}`), + }, } for _, test := range testCases { From 5ea04fe459a644035d6057ef4b75d9dfda92f004 Mon Sep 17 00:00:00 2001 From: andreasgreen <andreas.green@gmail.com> Date: Tue, 18 Nov 2025 21:57:17 +0100 Subject: [PATCH 127/272] BidTheatre: Update endpoint and add redirect user sync (#4562) --- static/bidder-info/bidtheatre.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/bidder-info/bidtheatre.yaml b/static/bidder-info/bidtheatre.yaml index a0f0cc2d21..74b51eff57 100644 --- a/static/bidder-info/bidtheatre.yaml +++ b/static/bidder-info/bidtheatre.yaml @@ -1,4 +1,4 @@ -endpoint: "https://prebidjs-bids.bidtheatre.net/prebidjsbid" +endpoint: "https://client-bids.adsby.bidtheatre.com/prebidjsbid" geoscope: - EEA maintainer: @@ -15,6 +15,6 @@ capabilities: - banner - video userSync: - # bidtheatre supports user syncing, but requires configuration. Please contact operations@bidtheatre.com. - supports: - - redirect + redirect: + url: "https://match.adsby.bidtheatre.com/prebidmatch?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redir={{.RedirectURL}}" + userMacro: "$UID" From db40c2e464b1d18e30897869fe47b6db4f3d8a4c Mon Sep 17 00:00:00 2001 From: Alessandro Rosetti <alessandro.rosetti@gmail.com> Date: Tue, 18 Nov 2025 22:38:10 +0100 Subject: [PATCH 128/272] CWire: Add userSync (#4516) --- static/bidder-info/cwire.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/static/bidder-info/cwire.yaml b/static/bidder-info/cwire.yaml index cedb6e3119..b7a16e05c3 100644 --- a/static/bidder-info/cwire.yaml +++ b/static/bidder-info/cwire.yaml @@ -10,4 +10,11 @@ capabilities: - banner site: mediaTypes: - - banner \ No newline at end of file + - banner +userSync: + iframe: + url: https://prebid.cwi.re/v1/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&rd={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://prebid.cwi.re/v1/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&rd={{.RedirectURL}} + userMacro: $UID \ No newline at end of file From c9b63e1befd7bfe34d685d0e1102d1357f13f55a Mon Sep 17 00:00:00 2001 From: cto-clydo <cto@clydo.io> Date: Thu, 20 Nov 2025 00:00:02 +0200 Subject: [PATCH 129/272] New Adapter: Clydo (#4535) --- adapters/clydo/clydo.go | 273 ++++++++++++++++++ adapters/clydo/clydo_test.go | 30 ++ .../exemplary/banner-multiple-app.json | 264 +++++++++++++++++ .../exemplary/banner-multiple-web.json | 261 +++++++++++++++++ .../exemplary/banner-single-app.json | 147 ++++++++++ .../exemplary/banner-single-web.json | 145 ++++++++++ .../exemplary/native-multiple-app.json | 272 +++++++++++++++++ .../exemplary/native-multiple-web.json | 269 +++++++++++++++++ .../exemplary/native-single-app.json | 151 ++++++++++ .../exemplary/native-single-web.json | 149 ++++++++++ .../exemplary/video-multiple-app.json | 264 +++++++++++++++++ .../exemplary/video-multiple-web.json | 261 +++++++++++++++++ .../clydotest/exemplary/video-single-app.json | 147 ++++++++++ .../clydotest/exemplary/video-single-web.json | 145 ++++++++++ .../supplemental/ext-bidder-invalid.json | 56 ++++ .../supplemental/ext-bidder-missing.json | 54 ++++ .../supplemental/ext-invalid-partner.json | 56 ++++ .../clydotest/supplemental/ext-missing.json | 51 ++++ .../clydotest/supplemental/no-currency.json | 144 +++++++++ .../clydotest/supplemental/no-device.json | 49 ++++ .../clydotest/supplemental/status-204.json | 113 ++++++++ .../clydotest/supplemental/status-400.json | 116 ++++++++ .../clydotest/supplemental/status-500.json | 116 ++++++++ adapters/clydo/params_test.go | 52 ++++ config/bidderinfo.go | 2 + exchange/adapter_builders.go | 2 + macros/macros.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_clydo.go | 6 + static/bidder-info/clydo.yaml | 26 ++ static/bidder-params/clydo.json | 21 ++ 31 files changed, 3646 insertions(+) create mode 100644 adapters/clydo/clydo.go create mode 100644 adapters/clydo/clydo_test.go create mode 100644 adapters/clydo/clydotest/exemplary/banner-multiple-app.json create mode 100644 adapters/clydo/clydotest/exemplary/banner-multiple-web.json create mode 100644 adapters/clydo/clydotest/exemplary/banner-single-app.json create mode 100644 adapters/clydo/clydotest/exemplary/banner-single-web.json create mode 100644 adapters/clydo/clydotest/exemplary/native-multiple-app.json create mode 100644 adapters/clydo/clydotest/exemplary/native-multiple-web.json create mode 100644 adapters/clydo/clydotest/exemplary/native-single-app.json create mode 100644 adapters/clydo/clydotest/exemplary/native-single-web.json create mode 100644 adapters/clydo/clydotest/exemplary/video-multiple-app.json create mode 100644 adapters/clydo/clydotest/exemplary/video-multiple-web.json create mode 100644 adapters/clydo/clydotest/exemplary/video-single-app.json create mode 100644 adapters/clydo/clydotest/exemplary/video-single-web.json create mode 100644 adapters/clydo/clydotest/supplemental/ext-bidder-invalid.json create mode 100644 adapters/clydo/clydotest/supplemental/ext-bidder-missing.json create mode 100644 adapters/clydo/clydotest/supplemental/ext-invalid-partner.json create mode 100644 adapters/clydo/clydotest/supplemental/ext-missing.json create mode 100644 adapters/clydo/clydotest/supplemental/no-currency.json create mode 100644 adapters/clydo/clydotest/supplemental/no-device.json create mode 100644 adapters/clydo/clydotest/supplemental/status-204.json create mode 100644 adapters/clydo/clydotest/supplemental/status-400.json create mode 100644 adapters/clydo/clydotest/supplemental/status-500.json create mode 100644 adapters/clydo/params_test.go create mode 100644 openrtb_ext/imp_clydo.go create mode 100644 static/bidder-info/clydo.yaml create mode 100644 static/bidder-params/clydo.json diff --git a/adapters/clydo/clydo.go b/adapters/clydo/clydo.go new file mode 100644 index 0000000000..0b06bd74d8 --- /dev/null +++ b/adapters/clydo/clydo.go @@ -0,0 +1,273 @@ +package clydo + +import ( + "fmt" + "net/http" + "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" +) + +type adapter struct { + endpoint *template.Template +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("Failed to parse endpoint url: %v", err) + } + bidder := &adapter{ + endpoint: template, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var requests []*adapters.RequestData + var errors []error + + impIds, err := prepareImpIds(request) + if err != nil { + return nil, append(errors, err) + } + + headers, err := prepareHeaders(request) + if err != nil { + return nil, append(errors, err) + } + + for _, imp := range request.Imp { + reqData, err := a.prepareRequest(request, imp, impIds, headers) + if err != nil { + errors = append(errors, err) + continue + } + requests = append(requests, reqData) + } + return requests, errors +} + +func (a *adapter) MakeBids( + request *openrtb2.BidRequest, + requestData *adapters.RequestData, + responseData *adapters.ResponseData, +) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if errResp := adapters.CheckResponseStatusCodeForErrors(responseData); errResp != nil { + return nil, []error{errResp} + } + response, err := prepareBidResponse(responseData.Body) + if err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + + bidTypeMap, err := buildBidTypeMap(request.Imp) + if err != nil { + return nil, []error{err} + } + bids := prepareSeatBids(response.SeatBid, bidTypeMap) + bidResponse.Bids = bids + + return bidResponse, nil +} + +func (a *adapter) prepareRequest(request *openrtb2.BidRequest, imp openrtb2.Imp, impIds []string, headers http.Header) (*adapters.RequestData, error) { + params, err := prepareExtParams(imp) + if err != nil { + return nil, err + } + endpoint, err := a.prepareEndpoint(params) + if err != nil { + return nil, err + } + body, err := prepareBody(request, imp) + if err != nil { + return nil, err + } + + return &adapters.RequestData{ + Method: "POST", + Uri: endpoint, + Body: body, + Headers: headers, + ImpIDs: impIds, + }, nil +} + +func prepareExtParams(imp openrtb2.Imp) (*openrtb_ext.ImpExtClydo, error) { + var clydoImpExt openrtb_ext.ImpExtClydo + var bidderExt adapters.ExtImpBidder + if len(imp.Ext) == 0 { + return nil, &errortypes.BadInput{ + Message: "missing ext", + } + } + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "invalid ext", + } + } + if len(bidderExt.Bidder) == 0 { + return nil, &errortypes.BadInput{ + Message: "missing ext.bidder", + } + } + if err := jsonutil.Unmarshal(bidderExt.Bidder, &clydoImpExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "invalid ext.bidder", + } + } + return &clydoImpExt, nil +} + +func (a *adapter) prepareEndpoint(params *openrtb_ext.ImpExtClydo) (string, error) { + partnerId := params.PartnerId + if partnerId == "" { + return "", &errortypes.BadInput{ + Message: "invalid partnerId", + } + } + + region := params.Region + if region == "" { + region = "us" + } + + endpointParams := macros.EndpointTemplateParams{ + PartnerId: partnerId, + Region: region, + } + return macros.ResolveMacros(a.endpoint, endpointParams) +} + +func prepareBody(request *openrtb2.BidRequest, imp openrtb2.Imp) ([]byte, error) { + reqCopy := *request + reqCopy.Imp = []openrtb2.Imp{imp} + + body, err := jsonutil.Marshal(&reqCopy) + if err != nil { + return nil, err + } + + return body, nil +} + +func prepareHeaders(request *openrtb2.BidRequest) (http.Header, error) { + allHeaders := map[string]string{ + "X-OpenRTB-Version": "2.5", + "Accept": "application/json", + "Content-Type": "application/json; charset=utf-8", + } + + allHeaders, err := appendDeviceHeaders(allHeaders, request) + if err != nil { + return nil, err + } + + headers := make(http.Header) + for k, v := range allHeaders { + headers.Add(k, v) + } + + return headers, nil +} + +func appendDeviceHeaders(headers map[string]string, request *openrtb2.BidRequest) (map[string]string, error) { + if request.Device == nil { + return nil, &errortypes.BadInput{Message: "Failed to get device headers"} + } + + if ipv6 := request.Device.IPv6; ipv6 != "" { + headers["X-Forwarded-For"] = ipv6 + } + if ip := request.Device.IP; ip != "" { + headers["X-Forwarded-For"] = ip + } + if ua := request.Device.UA; ua != "" { + headers["User-Agent"] = ua + } + + return headers, nil +} + +func prepareImpIds(request *openrtb2.BidRequest) ([]string, error) { + impIds := openrtb_ext.GetImpIDs(request.Imp) + if impIds == nil { + return nil, &errortypes.BadInput{Message: "Failed to get imp ids"} + } + return impIds, nil +} + +func prepareBidResponse(body []byte) (openrtb2.BidResponse, error) { + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(body, &response); err != nil { + return response, err + } + return response, nil +} + +func prepareSeatBids(seatBids []openrtb2.SeatBid, bidTypeMap map[string]openrtb_ext.BidType) []*adapters.TypedBid { + var typedBids []*adapters.TypedBid + + for _, seatBid := range seatBids { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + bidType := getMediaTypeForBid(bid, bidTypeMap) + typedBids = append(typedBids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + + return typedBids +} + +func buildBidTypeMap(imps []openrtb2.Imp) (map[string]openrtb_ext.BidType, error) { + bidTypeMap := make(map[string]openrtb_ext.BidType, len(imps)) + for _, imp := range imps { + if _, exists := bidTypeMap[imp.ID]; exists { + return nil, &errortypes.BadInput{ + Message: "Duplicate impression ID found", + } + } + + switch { + case imp.Audio != nil: + bidTypeMap[imp.ID] = openrtb_ext.BidTypeAudio + case imp.Video != nil: + bidTypeMap[imp.ID] = openrtb_ext.BidTypeVideo + case imp.Native != nil: + bidTypeMap[imp.ID] = openrtb_ext.BidTypeNative + case imp.Banner != nil: + bidTypeMap[imp.ID] = openrtb_ext.BidTypeBanner + default: + return nil, &errortypes.BadInput{ + Message: "Failed to get media type", + } + } + } + return bidTypeMap, nil +} + +func getMediaTypeForBid(bid *openrtb2.Bid, bidTypeMap map[string]openrtb_ext.BidType) openrtb_ext.BidType { + if mediaType, ok := bidTypeMap[bid.ImpID]; ok { + return mediaType + } + return openrtb_ext.BidTypeBanner +} diff --git a/adapters/clydo/clydo_test.go b/adapters/clydo/clydo_test.go new file mode 100644 index 0000000000..ef21d1e486 --- /dev/null +++ b/adapters/clydo/clydo_test.go @@ -0,0 +1,30 @@ +package clydo + +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/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderClydo, config.Adapter{ + Endpoint: "http://{{.Region}}.clydo.io/{{.PartnerId}}"}, + config.Server{ExternalUrl: "http://hosturl.com"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "clydotest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderClydo, config.Adapter{ + Endpoint: "{{Malformed}}"}, + config.Server{ExternalUrl: "http://hosturl.com"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/clydo/clydotest/exemplary/banner-multiple-app.json b/adapters/clydo/clydotest/exemplary/banner-multiple-app.json new file mode 100644 index 0000000000..0cae24f6ca --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/banner-multiple-app.json @@ -0,0 +1,264 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/banner-multiple-web.json b/adapters/clydo/clydotest/exemplary/banner-multiple-web.json new file mode 100644 index 0000000000..6c5a5a8160 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/banner-multiple-web.json @@ -0,0 +1,261 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/banner-single-app.json b/adapters/clydo/clydotest/exemplary/banner-single-app.json new file mode 100644 index 0000000000..5c3f4c0ec3 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/banner-single-app.json @@ -0,0 +1,147 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/banner-single-web.json b/adapters/clydo/clydotest/exemplary/banner-single-web.json new file mode 100644 index 0000000000..8bca61e84d --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/banner-single-web.json @@ -0,0 +1,145 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/native-multiple-app.json b/adapters/clydo/clydotest/exemplary/native-multiple-app.json new file mode 100644 index 0000000000..180da2ea35 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/native-multiple-app.json @@ -0,0 +1,272 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ipv6": "5165:6c58:9bc0:bb13:8b4f:01a1:2c55:ddb2", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["5165:6c58:9bc0:bb13:8b4f:01a1:2c55:ddb2"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ipv6": "5165:6c58:9bc0:bb13:8b4f:01a1:2c55:ddb2", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["5165:6c58:9bc0:bb13:8b4f:01a1:2c55:ddb2"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ipv6": "5165:6c58:9bc0:bb13:8b4f:01a1:2c55:ddb2", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/native-multiple-web.json b/adapters/clydo/clydotest/exemplary/native-multiple-web.json new file mode 100644 index 0000000000..7c8f51cd98 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/native-multiple-web.json @@ -0,0 +1,269 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/native-single-app.json b/adapters/clydo/clydotest/exemplary/native-single-app.json new file mode 100644 index 0000000000..97affd3f62 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/native-single-app.json @@ -0,0 +1,151 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/native-single-web.json b/adapters/clydo/clydotest/exemplary/native-single-web.json new file mode 100644 index 0000000000..9d9286f31b --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/native-single-web.json @@ -0,0 +1,149 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "native": { + "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", + "ver": "1.2", + "api": [ + 3, + 5, + 6, + 7 + ] + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "native", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "native" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/video-multiple-app.json b/adapters/clydo/clydotest/exemplary/video-multiple-app.json new file mode 100644 index 0000000000..a09b2ba682 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/video-multiple-app.json @@ -0,0 +1,264 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/video-multiple-web.json b/adapters/clydo/clydotest/exemplary/video-multiple-web.json new file mode 100644 index 0000000000..4298965d1a --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/video-multiple-web.json @@ -0,0 +1,261 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }, + { + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + } + ], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }, { + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3", "1753f913-d9ac-4d2b-93d2-475ff35c6ada"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + }, + { + "bids": [{ + "bid": { + "id": "test-id", + "impid": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + } + ] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/video-single-app.json b/adapters/clydo/clydotest/exemplary/video-single-app.json new file mode 100644 index 0000000000..e6a3e519f0 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/video-single-app.json @@ -0,0 +1,147 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/exemplary/video-single-web.json b/adapters/clydo/clydotest/exemplary/video-single-web.json new file mode 100644 index 0000000000..7861c2e683 --- /dev/null +++ b/adapters/clydo/clydotest/exemplary/video-single-web.json @@ -0,0 +1,145 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "video": { + "mimes": [ + "video/mp4" + ], + "placement": 1, + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "site": { + "domain": "site.com", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "video", + "seat": "clydo" + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/ext-bidder-invalid.json b/adapters/clydo/clydotest/supplemental/ext-bidder-invalid.json new file mode 100644 index 0000000000..78f9ad01f2 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/ext-bidder-invalid.json @@ -0,0 +1,56 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "invalid ext.bidder", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": 1 + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/ext-bidder-missing.json b/adapters/clydo/clydotest/supplemental/ext-bidder-missing.json new file mode 100644 index 0000000000..1b46c60f7b --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/ext-bidder-missing.json @@ -0,0 +1,54 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "missing ext.bidder", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "prebid": {} + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/ext-invalid-partner.json b/adapters/clydo/clydotest/supplemental/ext-invalid-partner.json new file mode 100644 index 0000000000..10591df1e5 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/ext-invalid-partner.json @@ -0,0 +1,56 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "invalid partnerId", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "placement": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/ext-missing.json b/adapters/clydo/clydotest/supplemental/ext-missing.json new file mode 100644 index 0000000000..7ee73546d6 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/ext-missing.json @@ -0,0 +1,51 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "missing ext", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD" + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/no-currency.json b/adapters/clydo/clydotest/supplemental/no-currency.json new file mode 100644 index 0000000000..bf86963b43 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/no-currency.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [{ + "bid": [{ + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }], + "type": "banner", + "seat": "clydo" + }] + } + } + }], + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "id": "test-id", + "impid": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "price": 1.5, + "adm": "test-adm", + "adomain": ["test.com"], + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/no-device.json b/adapters/clydo/clydotest/supplemental/no-device.json new file mode 100644 index 0000000000..6364a63555 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/no-device.json @@ -0,0 +1,49 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "Failed to get device headers", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff", + "region": "us" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/status-204.json b/adapters/clydo/clydotest/supplemental/status-204.json new file mode 100644 index 0000000000..d4d774e3b8 --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/status-204.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 204 + } + }], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/status-400.json b/adapters/clydo/clydotest/supplemental/status-400.json new file mode 100644 index 0000000000..391fc0353d --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/status-400.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 400 + } + }], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/clydo/clydotest/supplemental/status-500.json b/adapters/clydo/clydotest/supplemental/status-500.json new file mode 100644 index 0000000000..9747fcf79f --- /dev/null +++ b/adapters/clydo/clydotest/supplemental/status-500.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": ["application/json; charset=utf-8"], + "User-Agent": ["test-ua"], + "Accept": ["application/json"], + "X-Forwarded-For": ["111.222.333.444"], + "X-Openrtb-Version": ["2.5"] + }, + "uri": "http://us.clydo.io/rh7cnxlpvbjqU5ff", + "body": { + "id": "de825c88-282e-439a-bcf1-3108344f260c", + "imp": [{ + "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }], + "w": 320, + "h": 50 + }, + "bidfloor": 0.111, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "partnerId": "rh7cnxlpvbjqU5ff" + } + } + }], + "app": { + "bundle": "com.bundle.app", + "storeurl": "https://play.google.com/store/apps/details?id=com.bundle.app&hl=en", + "publisher": { + "id": "1122334444" + } + }, + "device": { + "lmt": 0, + "ua": "test-ua", + "ip": "111.222.333.444", + "h": 2082, + "w": 1080, + "ifa": "eb6685ef-b9d0-48b9-a1c2-db7894790f93" + }, + "user": { + "id": "f102c5fe-3d9e-4d14-89f3-8d55248246c7" + }, + "tmax": 1000, + "regs": { + "ext": { + "coppa": 0, + "gdpr": 0, + "us_privacy": "1YN-" + } + } + }, + "impIDs": ["224b15d9-c927-4cf7-aee3-9bea24c6f3e3"] + }, + "mockResponse": { + "status": 500 + } + }], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/clydo/params_test.go b/adapters/clydo/params_test.go new file mode 100644 index 0000000000..779c7eeadd --- /dev/null +++ b/adapters/clydo/params_test.go @@ -0,0 +1,52 @@ +package clydo + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderClydo, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderClydo, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"partnerId": "rxeMfUb992Ocxm9C"}`, + `{"partnerId": "jDrTOH0ADArSEqrR"}`, + `{"partnerId": "MZP6aFUyHqjoqMCs"}`, + `{"partnerId": "rxeMfUb992Ocxm9C", "region": "us"}`, + `{"partnerId": "rxeMfUb992Ocxm9C", "region": "usw"}`, + `{"partnerId": "jDrTOH0ADArSEqrR", "region": "eu"}`, + `{"partnerId": "MZP6aFUyHqjoqMCs", "region": "apac"}`, +} + +var invalidParams = []string{ + `{"partnerId": ""}`, + `{"partnerId": 111}`, + `{"partnerId": "rxeMfUb992Ocxm9C", "region": "uswest"}`, + `{"partnerId": "rxeMfUb992Ocxm9C", "region": "europa"}`, + `{"partnerId": "rxeMfUb992Ocxm9C", "region": "singapore"}`, +} diff --git a/config/bidderinfo.go b/config/bidderinfo.go index ff38be125d..8e873cbd04 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -438,6 +438,8 @@ var testEndpointTemplateParams = macros.EndpointTemplateParams{ SourceId: "anySourceID", AdUnit: "anyAdUnit", MediaType: "MediaType", + Region: "anyRegion", + PartnerId: "anyPartnerId", } // validateAdapterEndpoint makes sure that an adapter has a valid endpoint diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index fa3f6d8370..4533be19f9 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -76,6 +76,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/bwx" cadentaperturemx "github.com/prebid/prebid-server/v3/adapters/cadent_aperture_mx" "github.com/prebid/prebid-server/v3/adapters/ccx" + "github.com/prebid/prebid-server/v3/adapters/clydo" "github.com/prebid/prebid-server/v3/adapters/cointraffic" "github.com/prebid/prebid-server/v3/adapters/coinzilla" "github.com/prebid/prebid-server/v3/adapters/colossus" @@ -344,6 +345,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBWX: bwx.Builder, openrtb_ext.BidderCadentApertureMX: cadentaperturemx.Builder, openrtb_ext.BidderCcx: ccx.Builder, + openrtb_ext.BidderClydo: clydo.Builder, openrtb_ext.BidderCointraffic: cointraffic.Builder, openrtb_ext.BidderCoinzilla: coinzilla.Builder, openrtb_ext.BidderColossus: colossus.Builder, diff --git a/macros/macros.go b/macros/macros.go index f24974b572..0c6e08cae0 100644 --- a/macros/macros.go +++ b/macros/macros.go @@ -22,6 +22,8 @@ type EndpointTemplateParams struct { SspID string SeatID string TokenID string + PartnerId string + Region string PlacementID string } diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index d9df5e8909..7ccc446d79 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -92,6 +92,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderBWX, BidderCadentApertureMX, BidderCcx, + BidderClydo, BidderCointraffic, BidderCoinzilla, BidderColossus, @@ -467,6 +468,7 @@ const ( BidderBWX BidderName = "bwx" BidderCadentApertureMX BidderName = "cadent_aperture_mx" BidderCcx BidderName = "ccx" + BidderClydo BidderName = "clydo" BidderCointraffic BidderName = "cointraffic" BidderCoinzilla BidderName = "coinzilla" BidderColossus BidderName = "colossus" diff --git a/openrtb_ext/imp_clydo.go b/openrtb_ext/imp_clydo.go new file mode 100644 index 0000000000..74f244e438 --- /dev/null +++ b/openrtb_ext/imp_clydo.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtClydo struct { + PartnerId string `json:"partnerId"` + Region string `json:"region,omitempty"` +} diff --git a/static/bidder-info/clydo.yaml b/static/bidder-info/clydo.yaml new file mode 100644 index 0000000000..906f241799 --- /dev/null +++ b/static/bidder-info/clydo.yaml @@ -0,0 +1,26 @@ +# We have the following regional endpoint domains: +# US East: us +# US West: usw +# EU: eu +# APAC: apac +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +endpoint: 'http://{{.Region}}.clydo.io/{{.PartnerId}}' +endpointCompression: gzip +geoscope: + - global +maintainer: + email: cto@clydo.io +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + - audio + - native + site: + mediaTypes: + - banner + - video + - audio + - native \ No newline at end of file diff --git a/static/bidder-params/clydo.json b/static/bidder-params/clydo.json new file mode 100644 index 0000000000..8d7e016391 --- /dev/null +++ b/static/bidder-params/clydo.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Clydo Adapter Params", + "description": "A schema which validates params accepted by the Clydo adapter", + "type": "object", + + "properties": { + "partnerId": { + "type": "string", + "description": "Partner ID", + "minLength": 1 + }, + "region": { + "type": "string", + "description": "Regional endpoint identifier (us, usw, eu, apac)", + "enum": ["us", "usw", "eu", "apac"] + } + }, + + "required": ["partnerId"] +} \ No newline at end of file From be0a6b2151dd162934a55f3cfe04e748369210d7 Mon Sep 17 00:00:00 2001 From: Scott Kay <noreply@syntaxnode.com> Date: Fri, 21 Nov 2025 11:24:15 -0500 Subject: [PATCH 130/272] New Adapter: Microsoft (msft) (#4592) --- adapters/adapterstest/test_json.go | 41 +- .../adftest/supplemental/nobid-response.json | 2 +- .../exemplary/multiformat-impression.json | 3 +- .../exemplary/single-video-impression.json | 3 +- .../adponetest/exemplary/simple-banner.json | 2 +- .../aduptechtest/exemplary/simple-native.json | 2 +- .../supplemental/unsupported-mtype.json | 2 +- .../adverxo/adverxotest/exemplary/banner.json | 1 + .../adverxo/adverxotest/exemplary/native.json | 1 + .../adverxo/adverxotest/exemplary/video.json | 3 +- .../supplemental/wrong-bid-ext.json | 3 +- .../video/video-brand-category.json | 1 + .../exemplary/app-multi-impressions.json | 6 +- .../supplemental/media-type-absent.json | 3 +- .../supplemental/media-type-mapping.json | 3 +- .../avocet/avocettest/exemplary/video.json | 5 +- .../supplemental/multiple_format_request.json | 2 +- .../bluetest/exemplary/simple-web-banner.json | 3 +- .../exemplary/banner-multiple-app.json | 2 +- .../exemplary/banner-multiple-web.json | 2 +- .../exemplary/native-multiple-app.json | 2 +- .../exemplary/native-multiple-web.json | 2 +- .../exemplary/video-multiple-app.json | 2 +- .../exemplary/video-multiple-web.json | 2 +- adapters/criteo/criteo_test.go | 1 - .../exemplary/simple-banner-cookie-uid.json | 2 +- .../exemplary/simple-banner-inapp.json | 2 +- .../simple-banner-multiple-bids.json | 2 +- .../exemplary/simple-banner-paapi.json | 2 +- .../exemplary/simple-banner-uid.json | 2 +- .../exemplary/simple-multi-type-banner.json | 2 +- .../exemplary/simple-multi-type-video.json | 2 +- .../criteotest/exemplary/simple-video.json | 2 +- .../supplemental/simple-banner-with-ipv6.json | 2 +- .../supplemental/nobid-response.json | 2 +- .../freewheelssptest/exemplary/multi-imp.json | 2 +- .../exemplary/single-imp.json | 2 +- .../exemplary/string-single-imp.json | 2 +- .../supplemental/empty_object_response.json | 2 +- .../supplemental/missing_bid_ext.json | 3 +- .../supplemental/unknown_imp_media_type.json | 3 +- .../goldbachtest/exemplary/banner.json | 3 +- .../goldbachtest/exemplary/mixed.json | 3 +- .../exemplary/multiple-publisher.json | 6 +- .../goldbachtest/exemplary/native.json | 3 +- .../goldbachtest/exemplary/video.json | 3 +- .../huaweiadstest/exemplary/banner1.json | 2 +- .../exemplary/banner1_without_userext.json | 2 +- .../huaweiadstest/exemplary/banner2.json | 2 +- .../huaweiadstest/exemplary/banner3.json | 2 +- .../exemplary/banner4_mccmnc.json | 2 +- .../exemplary/banner5_user_geo.json | 2 +- .../huaweiadstest/exemplary/banner6_imei.json | 2 +- .../exemplary/bannerAppPromotionType.json | 2 +- .../exemplary/bannerNonIntegerMccmnc.json | 2 +- .../exemplary/bannerNotAppPromotionType.json | 2 +- .../exemplary/bannerTestExtraInfo1.json | 2 +- .../exemplary/bannerTestExtraInfo2.json | 2 +- .../exemplary/bannerTestExtraInfo3.json | 2 +- .../exemplary/bannerWrongMccmnc.json | 2 +- .../exemplary/interstitialBannerType.json | 2 +- .../exemplary/interstitialVideoType.json | 2 +- .../exemplary/nativeIncludeVideo.json | 2 +- .../exemplary/nativeMultiSizesByRange.json | 2 +- .../exemplary/nativeMultiSizesByRatio.json | 2 +- .../exemplary/nativeSingleImage.json | 2 +- .../exemplary/nativeThreeImage.json | 2 +- .../nativeThreeImageIncludeIcon.json | 2 +- .../exemplary/rewardedVideo.json | 2 +- .../exemplary/rewardedVideo1.json | 2 +- .../exemplary/rewardedVideo2.json | 2 +- .../exemplary/rewardedVideo3.json | 2 +- .../exemplary/rewardedVideo4.json | 2 +- .../huaweiadstest/exemplary/rollVideo.json | 2 +- .../huaweiadstest/exemplary/video.json | 2 +- .../bad_response_dont_find_impid.json | 2 +- .../bad_response_retcode30_204.json | 2 +- .../supplemental/missing_video_size.json | 2 +- .../supplemental/zero_video_size.json | 2 +- .../supplemental/dealid.json | 50 +- .../invibes/invibestest/exemplary/no-ad.json | 2 +- .../kidoztest/exemplary/simple-banner.json | 2 +- .../kidoztest/exemplary/simple-video.json | 2 +- .../supplemental/empty_object_response.json | 2 +- .../supplemental/unknown_bid_impid.json | 3 +- .../supplemental/unknown_imp_media_type.json | 3 +- .../loyal/loyaltest/exemplary/multi-imp.json | 20 +- .../mgidtest/exemplary/noplacementid.json | 3 +- .../mgidtest/exemplary/simple-banner.json | 3 +- .../exemplary/simple-banner_no_device.json | 3 +- .../simple-banner_no_device_no_site.json | 3 +- .../exemplary/simple-banner_with_crtype.json | 3 +- adapters/msft/iab_categories.go | 106 ++++ adapters/msft/models.go | 60 +++ adapters/msft/msft.go | 395 +++++++++++++++ adapters/msft/msft_test.go | 77 +++ adapters/msft/params_test.go | 79 +++ .../exemplary/simple-banner.json | 153 ++++++ .../test-extrainfo/video/simple-video.json | 168 +++++++ adapters/msft/test/amp/simple-banner.json | 154 ++++++ adapters/msft/test/exemplary/all-params.json | 182 +++++++ .../msft/test/exemplary/simple-banner.json | 153 ++++++ .../msft/test/exemplary/simple-native.json | 139 ++++++ .../msft/test/exemplary/simple-video.json | 168 +++++++ .../banner-api-not-overridden.json | 170 +++++++ .../bid-cat-brand-category-override.json | 156 ++++++ .../test/supplemental/bid-cat-multiple.json | 152 ++++++ adapters/msft/test/supplemental/bid-cat.json | 154 ++++++ .../test/supplemental/bid-type-invalid.json | 126 +++++ ...aymanagerver-generated-missing-source.json | 163 +++++++ ...ymanagerver-generated-missing-version.json | 163 +++++++ ...laymanagerver-generated-multiple-imps.json | 210 ++++++++ .../displaymanagerver-generated.json | 166 +++++++ .../supplemental/explicit-dimensions.json | 155 ++++++ .../test/supplemental/foreign-currency.json | 153 ++++++ .../test/supplemental/gpid-passthrough.json | 155 ++++++ .../test/supplemental/imps-none-valid.json | 55 +++ .../supplemental/include-brand-category.json | 175 +++++++ .../supplemental/inv-code-overridden.json | 158 ++++++ .../test/supplemental/member-id-conflict.json | 58 +++ .../msft/test/supplemental/member-id.json | 153 ++++++ .../msft/test/supplemental/multi-bid.json | 211 ++++++++ .../request-ext-appnexus-invalid.json | 40 ++ .../request-ext-appnexus-passthrough.json | 159 ++++++ .../test/supplemental/request-splitting.json | 459 ++++++++++++++++++ .../msft/test/supplemental/status-400.json | 83 ++++ .../supplemental/unmapped-brand-category.json | 150 ++++++ adapters/msft/test/video/simple-video.json | 168 +++++++ .../exemplary/simple-banner-cookie-uid.json | 2 +- .../simple-banner-multiple-bids.json | 2 +- .../simple-banner-uid-with-publisher-id.json | 2 +- .../omstest/exemplary/simple-banner-uid.json | 2 +- .../exemplary/simple-multi-type-banner.json | 2 +- .../oms/omstest/exemplary/simple-video.json | 2 +- .../supplemental/simple-banner-with-ipv6.json | 2 +- .../onetagtest/exemplary/simple-banner.json | 6 +- .../multibid-multi-format-with-mtype.json | 2 +- .../playdigotest/exemplary/multi-imp.json | 20 +- .../pubrisetest/exemplary/multi-imp.json | 20 +- .../exemplary/single-banner-app.json | 3 +- .../single-banner-defaultCurrency.json | 3 +- .../exemplary/single-banner-deviceConfig.json | 3 +- .../exemplary/single-banner-extUser.json | 3 +- .../exemplary/single-banner-floorPrice.json | 3 +- .../exemplary/single-banner-iPv6.json | 3 +- .../exemplary/single-banner-nil-device.json | 3 +- .../exemplary/single-banner-nosecure.json | 3 +- .../exemplary/single-banner-setCurrency.json | 3 +- .../exemplary/single-banner-sitePage.json | 3 +- .../exemplary/single-banner.json | 3 +- .../exemplary/single-video.json | 3 +- .../supplemental/bidTypeNotAssigned.json | 3 +- .../exemplary/simple-banner-inapp.json | 2 +- .../simple-banner-multiple-bids.json | 2 +- .../exemplary/simple-banner.json | 2 +- .../exemplary/simple-video.json | 2 +- .../supplemental/invalid-mtype.json | 2 +- .../exemplary/simple-banner-inapp.json | 2 +- ...mple-banner-multiple-bids-and-formats.json | 2 +- .../simple-banner-multiple-bids.json | 2 +- .../exemplary/simple-banner.json | 2 +- .../exemplary/simple-empty-publisherId.json | 2 +- .../exemplary/simple-multi-type-banner.json | 2 +- .../exemplary/simple-multi-type-video.json | 2 +- .../exemplary/simple-native.json | 2 +- .../exemplary/simple-video.json | 2 +- .../exemplary/use-supply-source-id-param.json | 2 +- .../auction-price-macro-replacement.json | 2 +- .../supplemental/invalid-mtype.json | 2 +- .../yieldmotest/exemplary/app-banner.json | 2 +- .../yieldmotest/exemplary/app_video.json | 2 +- .../yieldmotest/exemplary/simple-banner.json | 2 +- .../yieldmotest/exemplary/simple_video.json | 2 +- .../yieldmotest/exemplary/with_gpid.json | 2 +- config/adapter.go | 6 +- exchange/adapter_builders.go | 2 + exchange/exchange_test.go | 18 +- openrtb_ext/bidders.go | 2 + openrtb_ext/imp_msft.go | 18 + static/bidder-info/msft.yaml | 23 + static/bidder-params/msft.json | 68 +++ 181 files changed, 6017 insertions(+), 207 deletions(-) create mode 100644 adapters/msft/iab_categories.go create mode 100644 adapters/msft/models.go create mode 100644 adapters/msft/msft.go create mode 100644 adapters/msft/msft_test.go create mode 100644 adapters/msft/params_test.go create mode 100644 adapters/msft/test-extrainfo/exemplary/simple-banner.json create mode 100644 adapters/msft/test-extrainfo/video/simple-video.json create mode 100644 adapters/msft/test/amp/simple-banner.json create mode 100644 adapters/msft/test/exemplary/all-params.json create mode 100644 adapters/msft/test/exemplary/simple-banner.json create mode 100644 adapters/msft/test/exemplary/simple-native.json create mode 100644 adapters/msft/test/exemplary/simple-video.json create mode 100644 adapters/msft/test/supplemental/banner-api-not-overridden.json create mode 100644 adapters/msft/test/supplemental/bid-cat-brand-category-override.json create mode 100644 adapters/msft/test/supplemental/bid-cat-multiple.json create mode 100644 adapters/msft/test/supplemental/bid-cat.json create mode 100644 adapters/msft/test/supplemental/bid-type-invalid.json create mode 100644 adapters/msft/test/supplemental/displaymanagerver-generated-missing-source.json create mode 100644 adapters/msft/test/supplemental/displaymanagerver-generated-missing-version.json create mode 100644 adapters/msft/test/supplemental/displaymanagerver-generated-multiple-imps.json create mode 100644 adapters/msft/test/supplemental/displaymanagerver-generated.json create mode 100644 adapters/msft/test/supplemental/explicit-dimensions.json create mode 100644 adapters/msft/test/supplemental/foreign-currency.json create mode 100644 adapters/msft/test/supplemental/gpid-passthrough.json create mode 100644 adapters/msft/test/supplemental/imps-none-valid.json create mode 100644 adapters/msft/test/supplemental/include-brand-category.json create mode 100644 adapters/msft/test/supplemental/inv-code-overridden.json create mode 100644 adapters/msft/test/supplemental/member-id-conflict.json create mode 100644 adapters/msft/test/supplemental/member-id.json create mode 100644 adapters/msft/test/supplemental/multi-bid.json create mode 100644 adapters/msft/test/supplemental/request-ext-appnexus-invalid.json create mode 100644 adapters/msft/test/supplemental/request-ext-appnexus-passthrough.json create mode 100644 adapters/msft/test/supplemental/request-splitting.json create mode 100644 adapters/msft/test/supplemental/status-400.json create mode 100644 adapters/msft/test/supplemental/unmapped-brand-category.json create mode 100644 adapters/msft/test/video/simple-video.json create mode 100644 openrtb_ext/imp_msft.go create mode 100644 static/bidder-info/msft.yaml create mode 100644 static/bidder-params/msft.json diff --git a/adapters/adapterstest/test_json.go b/adapters/adapterstest/test_json.go index c2124abfca..05312bf29b 100644 --- a/adapters/adapterstest/test_json.go +++ b/adapters/adapterstest/test_json.go @@ -248,14 +248,31 @@ func assertMakeRequestsOutput(t *testing.T, filename string, actual []*adapters. t.Fatalf("%s: MakeRequests had wrong request count. Expected %d, got %d", filename, len(expected), len(actual)) } + // try to match expected to actual without assuming order, as the use of maps in some adapters purposely randomizes order. + expectedMatched := map[int]struct{}{} + actualMatched := map[int]struct{}{} for i := 0; i < len(expected); i++ { var err error for j := 0; j < len(actual); j++ { if err = diffHttpRequests(fmt.Sprintf("%s: httpRequest[%d]", filename, i), actual[j], &(expected[i].Request)); err == nil { + expectedMatched[i] = struct{}{} + actualMatched[j] = struct{}{} break } } - assert.NoError(t, err, fmt.Sprintf("%s Expected RequestData was not returned by adapters' MakeRequests() implementation: httpRequest[%d]", filename, i)) + assert.NoError(t, err, fmt.Sprintf("%s: Expected RequestData was not returned by adapters' MakeRequests() implementation: httpRequest[%d]", filename, i)) + } + + // verify all expected and actual were involved in a match + for i := 0; i < len(expected); i++ { + if _, ok := expectedMatched[i]; !ok { + t.Errorf("%s: Expected RequestData[%d] was not matched to a result", filename, i) + } + } + for i := 0; i < len(actual); i++ { + if _, ok := actualMatched[i]; !ok { + t.Errorf("%s: Actual RequestData[%d] was not matched to a result", filename, i) + } } } @@ -266,19 +283,22 @@ func assertErrorList(t *testing.T, description string, actual []error, expected t.Fatalf("%s had wrong error count. Expected %d, got %d (%v)", description, len(expected), len(actual), actual) } for i := 0; i < len(actual); i++ { - if expected[i].Comparison == "literal" { + switch expected[i].Comparison { + case "": + fallthrough + case "literal": if expected[i].Value != actual[i].Error() { t.Errorf(`%s error[%d] had wrong message. Expected "%s", got "%s"`, description, i, expected[i].Value, actual[i].Error()) } - } else if expected[i].Comparison == "regex" { + case "regex": if matched, _ := regexp.MatchString(expected[i].Value, actual[i].Error()); !matched { t.Errorf(`%s error[%d] had wrong message. Expected match with regex "%s", got "%s"`, description, i, expected[i].Value, actual[i].Error()) } - } else if expected[i].Comparison == "startswith" { + case "startswith": if !strings.HasPrefix(actual[i].Error(), expected[i].Value) { t.Errorf(`%s error[%d] had wrong message. Expected to start with "%s", got "%s"`, description, i, expected[i].Value, actual[i].Error()) } - } else { + default: t.Fatalf(`invalid comparison type "%s"`, expected[i].Comparison) } } @@ -286,12 +306,21 @@ func assertErrorList(t *testing.T, description string, actual []error, expected func assertMakeBidsOutput(t *testing.T, filename string, bidderResponse *adapters.BidderResponse, expected expectedBidResponse) { t.Helper() + + if expected.Currency != "" { + if !assert.Equal(t, expected.Currency, bidderResponse.Currency, "%s: Wrong MakeBids bidderResponse.Currency. Got %s, expected %s", filename, bidderResponse.Currency, expected.Currency) { + return + } + } + if !assert.Len(t, bidderResponse.Bids, len(expected.Bids), "%s: Wrong MakeBids bidderResponse.Bids count. len(bidderResponse.Bids) = %d vs len(spec.BidResponses.Bids) = %d", filename, len(bidderResponse.Bids), len(expected.Bids)) { return } + for i := 0; i < len(bidderResponse.Bids); i++ { diffBids(t, fmt.Sprintf("%s: typedBid[%d]", filename, i), bidderResponse.Bids[i], &(expected.Bids[i])) } + if expected.FledgeAuctionConfigs != nil { assert.NotNilf(t, bidderResponse.FledgeAuctionConfigs, "%s: expected fledgeauctionconfigs in bidderResponse", filename) fledgeAuctionConfigsJson, err := json.Marshal(bidderResponse.FledgeAuctionConfigs) @@ -305,7 +334,6 @@ func assertMakeBidsOutput(t *testing.T, filename string, bidderResponse *adapter // diffHttpRequests compares the actual HTTP request data to the expected one. // It assumes that the request bodies are JSON func diffHttpRequests(description string, actual *adapters.RequestData, expected *httpRequest) error { - if actual == nil { return fmt.Errorf("Bidders cannot return nil HTTP calls. %s was nil.", description) } @@ -336,6 +364,7 @@ func diffHttpRequests(description string, actual *adapters.RequestData, expected if !cmp.Equal(expected.ImpIDs, actual.ImpIDs, opt) { return fmt.Errorf(`%s actual.ImpIDs "%q" do not match expected "%q"`, description, actual.ImpIDs, expected.ImpIDs) } + return diffJson(description, actual.Body, expected.Body) } diff --git a/adapters/adf/adftest/supplemental/nobid-response.json b/adapters/adf/adftest/supplemental/nobid-response.json index 800666615d..2245d9a8ab 100644 --- a/adapters/adf/adftest/supplemental/nobid-response.json +++ b/adapters/adf/adftest/supplemental/nobid-response.json @@ -45,6 +45,6 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], + "expectedBidResponses": [{"currency":"","bids":[]}], "expectedMakeBidsErrors": [] } diff --git a/adapters/adkernel/adkerneltest/exemplary/multiformat-impression.json b/adapters/adkernel/adkerneltest/exemplary/multiformat-impression.json index de40a0e94a..6dda91a355 100644 --- a/adapters/adkernel/adkerneltest/exemplary/multiformat-impression.json +++ b/adapters/adkernel/adkerneltest/exemplary/multiformat-impression.json @@ -125,7 +125,8 @@ ] } ], - "bidid": "wehM-93KGr0" + "bidid": "wehM-93KGr0", + "cur": "USD" } } } diff --git a/adapters/adkernel/adkerneltest/exemplary/single-video-impression.json b/adapters/adkernel/adkerneltest/exemplary/single-video-impression.json index f98d1747bc..3f48c23223 100644 --- a/adapters/adkernel/adkerneltest/exemplary/single-video-impression.json +++ b/adapters/adkernel/adkerneltest/exemplary/single-video-impression.json @@ -84,7 +84,8 @@ ] } ], - "bidid": "wehM-93KGr0" + "bidid": "wehM-93KGr0", + "cur": "USD" } } } diff --git a/adapters/adpone/adponetest/exemplary/simple-banner.json b/adapters/adpone/adponetest/exemplary/simple-banner.json index b6608558a4..040401b855 100644 --- a/adapters/adpone/adponetest/exemplary/simple-banner.json +++ b/adapters/adpone/adponetest/exemplary/simple-banner.json @@ -69,7 +69,7 @@ }], "expectedBidResponses": [{ - "currency": "EUR", + "currency": "USD", "bids": [{ "bid": { "id": "randomid", diff --git a/adapters/aduptech/aduptechtest/exemplary/simple-native.json b/adapters/aduptech/aduptechtest/exemplary/simple-native.json index 2c1086897f..2d7ab8496c 100644 --- a/adapters/aduptech/aduptechtest/exemplary/simple-native.json +++ b/adapters/aduptech/aduptechtest/exemplary/simple-native.json @@ -78,7 +78,7 @@ } }] }], - "currency": "EUR" + "cur": "EUR" } } }], diff --git a/adapters/aduptech/aduptechtest/supplemental/unsupported-mtype.json b/adapters/aduptech/aduptechtest/supplemental/unsupported-mtype.json index 5d4ab7bd7c..6e8ebee638 100644 --- a/adapters/aduptech/aduptechtest/supplemental/unsupported-mtype.json +++ b/adapters/aduptech/aduptechtest/supplemental/unsupported-mtype.json @@ -77,7 +77,7 @@ } }] }], - "currency": "EUR" + "cur": "EUR" } } }], diff --git a/adapters/adverxo/adverxotest/exemplary/banner.json b/adapters/adverxo/adverxotest/exemplary/banner.json index 8182e9f54a..a53d8f923e 100644 --- a/adapters/adverxo/adverxotest/exemplary/banner.json +++ b/adapters/adverxo/adverxotest/exemplary/banner.json @@ -96,6 +96,7 @@ ], "expectedBidResponses": [ { + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/adverxo/adverxotest/exemplary/native.json b/adapters/adverxo/adverxotest/exemplary/native.json index 325471c30c..e9df74b81d 100644 --- a/adapters/adverxo/adverxotest/exemplary/native.json +++ b/adapters/adverxo/adverxotest/exemplary/native.json @@ -96,6 +96,7 @@ ], "expectedBidResponses": [ { + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/adverxo/adverxotest/exemplary/video.json b/adapters/adverxo/adverxotest/exemplary/video.json index 046eadc1cd..a2c91fff78 100644 --- a/adapters/adverxo/adverxotest/exemplary/video.json +++ b/adapters/adverxo/adverxotest/exemplary/video.json @@ -62,7 +62,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/apacdex/apacdextest/supplemental/wrong-bid-ext.json b/adapters/apacdex/apacdextest/supplemental/wrong-bid-ext.json index 1af796e6a6..6d23de1159 100644 --- a/adapters/apacdex/apacdextest/supplemental/wrong-bid-ext.json +++ b/adapters/apacdex/apacdextest/supplemental/wrong-bid-ext.json @@ -62,7 +62,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/appnexus/appnexustest/video/video-brand-category.json b/adapters/appnexus/appnexustest/video/video-brand-category.json index e3ec0c4fb7..a909679656 100644 --- a/adapters/appnexus/appnexustest/video/video-brand-category.json +++ b/adapters/appnexus/appnexustest/video/video-brand-category.json @@ -29,6 +29,7 @@ } ], "ext": { + "appnexus": {}, "prebid": { "targeting": { "includebrandcategory": { diff --git a/adapters/aso/asotest/exemplary/app-multi-impressions.json b/adapters/aso/asotest/exemplary/app-multi-impressions.json index be13c78929..90fb9fa3f8 100644 --- a/adapters/aso/asotest/exemplary/app-multi-impressions.json +++ b/adapters/aso/asotest/exemplary/app-multi-impressions.json @@ -117,7 +117,8 @@ } ] } - ] + ], + "cur": "USD" } } }, @@ -173,7 +174,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/aso/asotest/supplemental/media-type-absent.json b/adapters/aso/asotest/supplemental/media-type-absent.json index 85ede039ff..1d5d38279a 100644 --- a/adapters/aso/asotest/supplemental/media-type-absent.json +++ b/adapters/aso/asotest/supplemental/media-type-absent.json @@ -66,7 +66,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/aso/asotest/supplemental/media-type-mapping.json b/adapters/aso/asotest/supplemental/media-type-mapping.json index f1a44c582b..28a79a4ca3 100644 --- a/adapters/aso/asotest/supplemental/media-type-mapping.json +++ b/adapters/aso/asotest/supplemental/media-type-mapping.json @@ -71,7 +71,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/avocet/avocettest/exemplary/video.json b/adapters/avocet/avocettest/exemplary/video.json index 2be9675750..21f2b97413 100644 --- a/adapters/avocet/avocettest/exemplary/video.json +++ b/adapters/avocet/avocettest/exemplary/video.json @@ -73,14 +73,15 @@ ], "seat": "TEST_SEAT_ID" } - ] + ], + "cur": "EUR" } } } ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/bliink/bliinktest/supplemental/multiple_format_request.json b/adapters/bliink/bliinktest/supplemental/multiple_format_request.json index c14e9cd887..2d708b29aa 100644 --- a/adapters/bliink/bliinktest/supplemental/multiple_format_request.json +++ b/adapters/bliink/bliinktest/supplemental/multiple_format_request.json @@ -117,7 +117,7 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], + "expectedBidResponses": [{"currency":"EUR","bids":[]}], "expectedMakeBidsErrors": [ { "value": "unable to fetch mediaType in multi-format: some-impression-id", diff --git a/adapters/blue/bluetest/exemplary/simple-web-banner.json b/adapters/blue/bluetest/exemplary/simple-web-banner.json index fec884fade..0481611ff0 100644 --- a/adapters/blue/bluetest/exemplary/simple-web-banner.json +++ b/adapters/blue/bluetest/exemplary/simple-web-banner.json @@ -83,7 +83,8 @@ } ] } - ] + ], + "cur": "BRL" } } } diff --git a/adapters/clydo/clydotest/exemplary/banner-multiple-app.json b/adapters/clydo/clydotest/exemplary/banner-multiple-app.json index 0cae24f6ca..5ee0cee6f4 100644 --- a/adapters/clydo/clydotest/exemplary/banner-multiple-app.json +++ b/adapters/clydo/clydotest/exemplary/banner-multiple-app.json @@ -161,7 +161,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "banner": { "format": [{ "w": 320, diff --git a/adapters/clydo/clydotest/exemplary/banner-multiple-web.json b/adapters/clydo/clydotest/exemplary/banner-multiple-web.json index 6c5a5a8160..5fd2f18abe 100644 --- a/adapters/clydo/clydotest/exemplary/banner-multiple-web.json +++ b/adapters/clydo/clydotest/exemplary/banner-multiple-web.json @@ -159,7 +159,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "banner": { "format": [{ "w": 320, diff --git a/adapters/clydo/clydotest/exemplary/native-multiple-app.json b/adapters/clydo/clydotest/exemplary/native-multiple-app.json index 180da2ea35..e7192f8f5c 100644 --- a/adapters/clydo/clydotest/exemplary/native-multiple-app.json +++ b/adapters/clydo/clydotest/exemplary/native-multiple-app.json @@ -167,7 +167,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "native": { "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", "ver": "1.2", diff --git a/adapters/clydo/clydotest/exemplary/native-multiple-web.json b/adapters/clydo/clydotest/exemplary/native-multiple-web.json index 7c8f51cd98..3b11cf7cbb 100644 --- a/adapters/clydo/clydotest/exemplary/native-multiple-web.json +++ b/adapters/clydo/clydotest/exemplary/native-multiple-web.json @@ -165,7 +165,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "native": { "request": "{\"ver\":\"1.1\",\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"data\":{\"type\":12}},{\"id\":2,\"required\":1,\"title\":{\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":80,\"h\":80}},{\"id\":4,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}},{\"id\":5,\"data\":{\"type\":3}},{\"id\":6,\"required\":1,\"data\":{\"type\":2,\"len\":150}}]}", "ver": "1.2", diff --git a/adapters/clydo/clydotest/exemplary/video-multiple-app.json b/adapters/clydo/clydotest/exemplary/video-multiple-app.json index a09b2ba682..d85e1eb332 100644 --- a/adapters/clydo/clydotest/exemplary/video-multiple-app.json +++ b/adapters/clydo/clydotest/exemplary/video-multiple-app.json @@ -161,7 +161,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "video": { "mimes": [ "video/mp4" diff --git a/adapters/clydo/clydotest/exemplary/video-multiple-web.json b/adapters/clydo/clydotest/exemplary/video-multiple-web.json index 4298965d1a..4442c88ef4 100644 --- a/adapters/clydo/clydotest/exemplary/video-multiple-web.json +++ b/adapters/clydo/clydotest/exemplary/video-multiple-web.json @@ -159,7 +159,7 @@ "body": { "id": "de825c88-282e-439a-bcf1-3108344f260c", "imp": [{ - "id": "224b15d9-c927-4cf7-aee3-9bea24c6f3e3", + "id": "1753f913-d9ac-4d2b-93d2-475ff35c6ada", "video": { "mimes": [ "video/mp4" diff --git a/adapters/criteo/criteo_test.go b/adapters/criteo/criteo_test.go index 66420429a9..70392c6cd5 100644 --- a/adapters/criteo/criteo_test.go +++ b/adapters/criteo/criteo_test.go @@ -13,7 +13,6 @@ import ( ) func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderCriteo, config.Adapter{ Endpoint: "https://ssp-bidder.criteo.com/openrtb/pbs/auction/request?profile=230"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) diff --git a/adapters/criteo/criteotest/exemplary/simple-banner-cookie-uid.json b/adapters/criteo/criteotest/exemplary/simple-banner-cookie-uid.json index 97f13a84ab..82ad75d6b5 100755 --- a/adapters/criteo/criteotest/exemplary/simple-banner-cookie-uid.json +++ b/adapters/criteo/criteotest/exemplary/simple-banner-cookie-uid.json @@ -78,7 +78,7 @@ "status": 200, "body": { "id": "test-request-id", - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-banner-inapp.json b/adapters/criteo/criteotest/exemplary/simple-banner-inapp.json index a1b6fad14d..8bf2aa7c40 100755 --- a/adapters/criteo/criteotest/exemplary/simple-banner-inapp.json +++ b/adapters/criteo/criteotest/exemplary/simple-banner-inapp.json @@ -71,7 +71,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-banner-multiple-bids.json b/adapters/criteo/criteotest/exemplary/simple-banner-multiple-bids.json index 6bf1fb89e2..beb0d2ec1f 100644 --- a/adapters/criteo/criteotest/exemplary/simple-banner-multiple-bids.json +++ b/adapters/criteo/criteotest/exemplary/simple-banner-multiple-bids.json @@ -133,7 +133,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-banner-paapi.json b/adapters/criteo/criteotest/exemplary/simple-banner-paapi.json index ea92a9026c..e1dc6de964 100644 --- a/adapters/criteo/criteotest/exemplary/simple-banner-paapi.json +++ b/adapters/criteo/criteotest/exemplary/simple-banner-paapi.json @@ -101,7 +101,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-banner-uid.json b/adapters/criteo/criteotest/exemplary/simple-banner-uid.json index 3b9edf5f07..cfa11d9e4a 100755 --- a/adapters/criteo/criteotest/exemplary/simple-banner-uid.json +++ b/adapters/criteo/criteotest/exemplary/simple-banner-uid.json @@ -99,7 +99,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-multi-type-banner.json b/adapters/criteo/criteotest/exemplary/simple-multi-type-banner.json index 5fc15fd1c1..369bdd4428 100644 --- a/adapters/criteo/criteotest/exemplary/simple-multi-type-banner.json +++ b/adapters/criteo/criteotest/exemplary/simple-multi-type-banner.json @@ -111,7 +111,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-multi-type-video.json b/adapters/criteo/criteotest/exemplary/simple-multi-type-video.json index d4f9c9683e..88b871b477 100644 --- a/adapters/criteo/criteotest/exemplary/simple-multi-type-video.json +++ b/adapters/criteo/criteotest/exemplary/simple-multi-type-video.json @@ -111,7 +111,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/exemplary/simple-video.json b/adapters/criteo/criteotest/exemplary/simple-video.json index 87c8d0ddea..be973bced8 100644 --- a/adapters/criteo/criteotest/exemplary/simple-video.json +++ b/adapters/criteo/criteotest/exemplary/simple-video.json @@ -95,7 +95,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/criteo/criteotest/supplemental/simple-banner-with-ipv6.json b/adapters/criteo/criteotest/supplemental/simple-banner-with-ipv6.json index b56da8a5f3..55821d6470 100755 --- a/adapters/criteo/criteotest/supplemental/simple-banner-with-ipv6.json +++ b/adapters/criteo/criteotest/supplemental/simple-banner-with-ipv6.json @@ -92,7 +92,7 @@ "status": 200, "body": { "id": "test-request-id", - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/dianomi/dianomitest/supplemental/nobid-response.json b/adapters/dianomi/dianomitest/supplemental/nobid-response.json index 3c8845163b..d5c2368da8 100644 --- a/adapters/dianomi/dianomitest/supplemental/nobid-response.json +++ b/adapters/dianomi/dianomitest/supplemental/nobid-response.json @@ -45,6 +45,6 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], + "expectedBidResponses": [{"currency":"","bids":[]}], "expectedMakeBidsErrors": [] } diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json index 18a1dbdbde..ebef49ba38 100644 --- a/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json +++ b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json @@ -118,7 +118,7 @@ "expectedBidResponses": [ { - "currency": "CUR", + "currency": "EUR", "bids": [ { "bid": { diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json index dd70cced61..4ff22d9d58 100644 --- a/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json +++ b/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json @@ -78,7 +78,7 @@ "expectedBidResponses": [ { - "currency": "CUR", + "currency": "EUR", "bids": [ { "bid": { diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json index c9b5d71519..d72fcff337 100644 --- a/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json +++ b/adapters/freewheelssp/freewheelssptest/exemplary/string-single-imp.json @@ -78,7 +78,7 @@ "expectedBidResponses": [ { - "currency": "CUR", + "currency": "EUR", "bids": [ { "bid": { diff --git a/adapters/frvradn/frvradntest/supplemental/empty_object_response.json b/adapters/frvradn/frvradntest/supplemental/empty_object_response.json index 8474132d08..72af05494c 100644 --- a/adapters/frvradn/frvradntest/supplemental/empty_object_response.json +++ b/adapters/frvradn/frvradntest/supplemental/empty_object_response.json @@ -53,5 +53,5 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}] + "expectedBidResponses": [{"currency":"","bids":[]}] } diff --git a/adapters/frvradn/frvradntest/supplemental/missing_bid_ext.json b/adapters/frvradn/frvradntest/supplemental/missing_bid_ext.json index 4326e57273..bc01795b36 100644 --- a/adapters/frvradn/frvradntest/supplemental/missing_bid_ext.json +++ b/adapters/frvradn/frvradntest/supplemental/missing_bid_ext.json @@ -68,7 +68,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/frvradn/frvradntest/supplemental/unknown_imp_media_type.json b/adapters/frvradn/frvradntest/supplemental/unknown_imp_media_type.json index b9584b5885..21e175e466 100644 --- a/adapters/frvradn/frvradntest/supplemental/unknown_imp_media_type.json +++ b/adapters/frvradn/frvradntest/supplemental/unknown_imp_media_type.json @@ -53,7 +53,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/goldbach/goldbachtest/exemplary/banner.json b/adapters/goldbach/goldbachtest/exemplary/banner.json index 23bbc5ef35..00dc5ce0db 100644 --- a/adapters/goldbach/goldbachtest/exemplary/banner.json +++ b/adapters/goldbach/goldbachtest/exemplary/banner.json @@ -96,7 +96,8 @@ } ] } - ] + ], + "cur": "CHF" } } } diff --git a/adapters/goldbach/goldbachtest/exemplary/mixed.json b/adapters/goldbach/goldbachtest/exemplary/mixed.json index 2f6995b728..0d6f2f14f9 100644 --- a/adapters/goldbach/goldbachtest/exemplary/mixed.json +++ b/adapters/goldbach/goldbachtest/exemplary/mixed.json @@ -140,7 +140,8 @@ } ] } - ] + ], + "cur": "CHF" } } } diff --git a/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json index 3ccf106116..46cc4a84ad 100644 --- a/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json +++ b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json @@ -101,7 +101,8 @@ } ] } - ] + ], + "cur": "CHF" } } }, @@ -167,7 +168,8 @@ } ] } - ] + ], + "cur": "CHF" } } } diff --git a/adapters/goldbach/goldbachtest/exemplary/native.json b/adapters/goldbach/goldbachtest/exemplary/native.json index 2c9c797ca6..4c8678d431 100644 --- a/adapters/goldbach/goldbachtest/exemplary/native.json +++ b/adapters/goldbach/goldbachtest/exemplary/native.json @@ -91,7 +91,8 @@ } ] } - ] + ], + "cur": "CHF" } } } diff --git a/adapters/goldbach/goldbachtest/exemplary/video.json b/adapters/goldbach/goldbachtest/exemplary/video.json index 7eaed83320..438d7ab07b 100644 --- a/adapters/goldbach/goldbachtest/exemplary/video.json +++ b/adapters/goldbach/goldbachtest/exemplary/video.json @@ -104,7 +104,8 @@ } ] } - ] + ], + "cur": "CHF" } } } diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner1.json b/adapters/huaweiads/huaweiadstest/exemplary/banner1.json index 1408de463a..cefdd9b931 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner1.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner1.json @@ -236,7 +236,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner1_without_userext.json b/adapters/huaweiads/huaweiadstest/exemplary/banner1_without_userext.json index b41ee04324..29ebacd46a 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner1_without_userext.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner1_without_userext.json @@ -229,7 +229,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner2.json b/adapters/huaweiads/huaweiadstest/exemplary/banner2.json index 6e2a2b6214..90146f80d2 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner2.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner2.json @@ -250,7 +250,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner3.json b/adapters/huaweiads/huaweiadstest/exemplary/banner3.json index 79e29ec696..10706e9b46 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner3.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner3.json @@ -249,7 +249,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner4_mccmnc.json b/adapters/huaweiads/huaweiadstest/exemplary/banner4_mccmnc.json index bf327366c6..5d91d3ccb6 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner4_mccmnc.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner4_mccmnc.json @@ -247,7 +247,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner5_user_geo.json b/adapters/huaweiads/huaweiadstest/exemplary/banner5_user_geo.json index 7f4e301829..a633718efa 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner5_user_geo.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner5_user_geo.json @@ -250,7 +250,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner6_imei.json b/adapters/huaweiads/huaweiadstest/exemplary/banner6_imei.json index 8814faba49..75dbdb734e 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/banner6_imei.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/banner6_imei.json @@ -240,7 +240,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerAppPromotionType.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerAppPromotionType.json index dc58891db6..ccfc278a56 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerAppPromotionType.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerAppPromotionType.json @@ -205,7 +205,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerNonIntegerMccmnc.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerNonIntegerMccmnc.json index 64a62268c3..a80c962d02 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerNonIntegerMccmnc.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerNonIntegerMccmnc.json @@ -247,7 +247,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerNotAppPromotionType.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerNotAppPromotionType.json index d4d7a298f8..9e9186e27d 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerNotAppPromotionType.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerNotAppPromotionType.json @@ -205,7 +205,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json index 10f41ad766..70d4e68a63 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json @@ -232,7 +232,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json index 5423de9fcd..915d1d8f07 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json @@ -250,7 +250,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json index 122583a057..890e6f3f48 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json @@ -250,7 +250,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerWrongMccmnc.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerWrongMccmnc.json index a56c0f8faf..2c032680a6 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/bannerWrongMccmnc.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerWrongMccmnc.json @@ -247,7 +247,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/interstitialBannerType.json b/adapters/huaweiads/huaweiadstest/exemplary/interstitialBannerType.json index 0b19c69d8b..52dffcfdea 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/interstitialBannerType.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/interstitialBannerType.json @@ -206,7 +206,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/interstitialVideoType.json b/adapters/huaweiads/huaweiadstest/exemplary/interstitialVideoType.json index d1486ae2be..77240e6807 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/interstitialVideoType.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/interstitialVideoType.json @@ -302,7 +302,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json index 453d872361..4b1098dbed 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json @@ -294,7 +294,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRange.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRange.json index 5dd77bf8fd..d312e966de 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRange.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRange.json @@ -284,7 +284,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRatio.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRatio.json index a6ba78f6fa..e728df0c0e 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRatio.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeMultiSizesByRatio.json @@ -284,7 +284,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json index 2a23420ff2..d958bc8714 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json @@ -295,7 +295,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json index 84e523e8bf..df40fba03c 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json @@ -326,7 +326,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json index 5a8722c6f7..20e39c3b09 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json @@ -314,7 +314,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo.json b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo.json index 0a23ca7c9d..4e87b1fcfd 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo.json @@ -302,7 +302,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo1.json b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo1.json index 26562f51d0..42874b6ea9 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo1.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo1.json @@ -293,7 +293,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo2.json b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo2.json index a911e38df7..d22c4e2a83 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo2.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo2.json @@ -277,7 +277,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo3.json b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo3.json index c2d8342cf3..23d78ee260 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo3.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo3.json @@ -284,7 +284,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo4.json b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo4.json index f61acf30c2..444a3dbf36 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo4.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rewardedVideo4.json @@ -283,7 +283,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/rollVideo.json b/adapters/huaweiads/huaweiadstest/exemplary/rollVideo.json index 20da7ddf37..06d7624432 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/rollVideo.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/rollVideo.json @@ -307,7 +307,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/exemplary/video.json b/adapters/huaweiads/huaweiadstest/exemplary/video.json index 74e7e7e6c2..53f2f60657 100644 --- a/adapters/huaweiads/huaweiadstest/exemplary/video.json +++ b/adapters/huaweiads/huaweiadstest/exemplary/video.json @@ -318,7 +318,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json index ec69e1fb14..51420f00cf 100644 --- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json +++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json @@ -321,7 +321,7 @@ ], "expectedBidResponses": [ { - "currency":"USD", + "currency":"CNY", "bids":[ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json index 2b7a78523f..30f3e42bec 100644 --- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json +++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json @@ -156,7 +156,7 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], + "expectedBidResponses": [{"currency":"CNY","bids":[]}], "expectedMakeRequestsErrors": [], "expectedMakeBidsErrors": [ ] diff --git a/adapters/huaweiads/huaweiadstest/supplemental/missing_video_size.json b/adapters/huaweiads/huaweiadstest/supplemental/missing_video_size.json index d32f1cf57e..efd62e5216 100644 --- a/adapters/huaweiads/huaweiadstest/supplemental/missing_video_size.json +++ b/adapters/huaweiads/huaweiadstest/supplemental/missing_video_size.json @@ -314,7 +314,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/huaweiads/huaweiadstest/supplemental/zero_video_size.json b/adapters/huaweiads/huaweiadstest/supplemental/zero_video_size.json index 4cbed97552..2c169e80ad 100644 --- a/adapters/huaweiads/huaweiadstest/supplemental/zero_video_size.json +++ b/adapters/huaweiads/huaweiadstest/supplemental/zero_video_size.json @@ -316,7 +316,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "CNY", "bids": [ { "bid": { diff --git a/adapters/improvedigital/improvedigitaltest/supplemental/dealid.json b/adapters/improvedigital/improvedigitaltest/supplemental/dealid.json index 631d59fb16..59fbe57242 100644 --- a/adapters/improvedigital/improvedigitaltest/supplemental/dealid.json +++ b/adapters/improvedigital/improvedigitaltest/supplemental/dealid.json @@ -14,7 +14,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-1", "banner": { "format": [ { @@ -30,7 +30,7 @@ } }, { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-2", "banner": { "format": [ { @@ -46,7 +46,7 @@ } }, { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-3", "banner": { "format": [ { @@ -62,7 +62,7 @@ } }, { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-4", "banner": { "format": [ { @@ -78,7 +78,7 @@ } }, { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-5", "banner": { "format": [ { @@ -114,7 +114,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-1", "banner": { "format": [ { @@ -131,7 +131,7 @@ } ] }, - "impIDs":["test-imp-id-banner"] + "impIDs":["test-imp-id-banner-1"] }, "mockResponse": { "status": 200, @@ -143,7 +143,7 @@ "bid": [ { "id": "randomid1", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-1", "price": 0.5, "adid": "12345678", "adm": "some-test-ad-html", @@ -186,7 +186,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-2", "banner": { "format": [ { @@ -203,7 +203,7 @@ } ] }, - "impIDs":["test-imp-id-banner"] + "impIDs":["test-imp-id-banner-2"] }, "mockResponse": { "status": 200, @@ -215,7 +215,7 @@ "bid": [ { "id": "randomid1", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-2", "price": 0.5, "adid": "12345678", "adm": "some-test-ad-html", @@ -258,7 +258,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-3", "banner": { "format": [ { @@ -275,7 +275,7 @@ } ] }, - "impIDs":["test-imp-id-banner"] + "impIDs":["test-imp-id-banner-3"] }, "mockResponse": { "status": 200, @@ -287,7 +287,7 @@ "bid": [ { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-3", "price": 0.5, "adid": "12345678", "adm": "some-test-ad-html", @@ -329,7 +329,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-4", "banner": { "format": [ { @@ -346,7 +346,7 @@ } ] }, - "impIDs":["test-imp-id-banner"] + "impIDs":["test-imp-id-banner-4"] }, "mockResponse": { "status": 200, @@ -358,7 +358,7 @@ "bid": [ { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-4", "price": 0.5, "adid": "12345678", "adm": "some-test-ad-html", @@ -401,7 +401,7 @@ }, "imp": [ { - "id": "test-imp-id-banner", + "id": "test-imp-id-banner-5", "banner": { "format": [ { @@ -418,7 +418,7 @@ } ] }, - "impIDs":["test-imp-id-banner"] + "impIDs":["test-imp-id-banner-5"] }, "mockResponse": { "status": 200, @@ -430,7 +430,7 @@ "bid": [ { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-5", "price": 0.5, "adid": "12345678", "adm": "some-test-ad-html", @@ -462,7 +462,7 @@ { "bid": { "id": "randomid1", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-1", "price": 0.5, "adm": "some-test-ad-html", "adid": "12345678", @@ -491,7 +491,7 @@ { "bid": { "id": "randomid1", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-2", "price": 0.5, "adm": "some-test-ad-html", "adid": "12345678", @@ -519,7 +519,7 @@ { "bid": { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-3", "price": 0.5, "adm": "some-test-ad-html", "adid": "12345678", @@ -546,7 +546,7 @@ { "bid": { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-4", "price": 0.5, "adm": "some-test-ad-html", "adid": "12345678", @@ -574,7 +574,7 @@ { "bid": { "id": "randomid", - "impid": "test-imp-id-banner", + "impid": "test-imp-id-banner-5", "price": 0.5, "adm": "some-test-ad-html", "adid": "12345678", diff --git a/adapters/invibes/invibestest/exemplary/no-ad.json b/adapters/invibes/invibestest/exemplary/no-ad.json index 386061147b..9648081da9 100644 --- a/adapters/invibes/invibestest/exemplary/no-ad.json +++ b/adapters/invibes/invibestest/exemplary/no-ad.json @@ -61,5 +61,5 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}] + "expectedBidResponses": [{"currency":"EUR","bids":[]}] } diff --git a/adapters/kidoz/kidoztest/exemplary/simple-banner.json b/adapters/kidoz/kidoztest/exemplary/simple-banner.json index 2f4195bdb3..0a6922f65d 100644 --- a/adapters/kidoz/kidoztest/exemplary/simple-banner.json +++ b/adapters/kidoz/kidoztest/exemplary/simple-banner.json @@ -71,7 +71,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/kidoz/kidoztest/exemplary/simple-video.json b/adapters/kidoz/kidoztest/exemplary/simple-video.json index c7be554542..401a9c94ae 100644 --- a/adapters/kidoz/kidoztest/exemplary/simple-video.json +++ b/adapters/kidoz/kidoztest/exemplary/simple-video.json @@ -69,7 +69,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/limelightDigital/LimelightDigitaltest/supplemental/empty_object_response.json b/adapters/limelightDigital/LimelightDigitaltest/supplemental/empty_object_response.json index 24b9dbe313..23ca7ae186 100644 --- a/adapters/limelightDigital/LimelightDigitaltest/supplemental/empty_object_response.json +++ b/adapters/limelightDigital/LimelightDigitaltest/supplemental/empty_object_response.json @@ -49,5 +49,5 @@ } } ], - "expectedBidResponses": [{"currency":"USD","bids":[]}] + "expectedBidResponses": [{"currency":"","bids":[]}] } diff --git a/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_bid_impid.json b/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_bid_impid.json index 1237d4be6c..418bded198 100644 --- a/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_bid_impid.json +++ b/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_bid_impid.json @@ -64,7 +64,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_imp_media_type.json b/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_imp_media_type.json index 09b5f9f685..dfec661e84 100644 --- a/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_imp_media_type.json +++ b/adapters/limelightDigital/LimelightDigitaltest/supplemental/unknown_imp_media_type.json @@ -48,7 +48,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/loyal/loyaltest/exemplary/multi-imp.json b/adapters/loyal/loyaltest/exemplary/multi-imp.json index 1423f5c9e4..97b64607ef 100644 --- a/adapters/loyal/loyaltest/exemplary/multi-imp.json +++ b/adapters/loyal/loyaltest/exemplary/multi-imp.json @@ -11,7 +11,7 @@ }, "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -32,7 +32,7 @@ } }, { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -62,7 +62,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -93,7 +93,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-1"] }, "mockResponse": { "status": 200, @@ -104,7 +104,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://us-east-1.loyal.app/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -133,7 +133,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -164,7 +164,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-2"] }, "mockResponse": { "status": 200, @@ -175,7 +175,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://us-east-1.loyal.app/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -204,7 +204,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://us-east-1.loyal.app/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -227,7 +227,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://us-east-1.loyal.app/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", diff --git a/adapters/mgid/mgidtest/exemplary/noplacementid.json b/adapters/mgid/mgidtest/exemplary/noplacementid.json index 48dfe5e462..0b1d7d0ca7 100644 --- a/adapters/mgid/mgidtest/exemplary/noplacementid.json +++ b/adapters/mgid/mgidtest/exemplary/noplacementid.json @@ -106,7 +106,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/mgid/mgidtest/exemplary/simple-banner.json b/adapters/mgid/mgidtest/exemplary/simple-banner.json index 3bc4389ad5..beb47648ea 100644 --- a/adapters/mgid/mgidtest/exemplary/simple-banner.json +++ b/adapters/mgid/mgidtest/exemplary/simple-banner.json @@ -108,7 +108,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/mgid/mgidtest/exemplary/simple-banner_no_device.json b/adapters/mgid/mgidtest/exemplary/simple-banner_no_device.json index 7a76a4386f..f580dcfcbf 100644 --- a/adapters/mgid/mgidtest/exemplary/simple-banner_no_device.json +++ b/adapters/mgid/mgidtest/exemplary/simple-banner_no_device.json @@ -102,7 +102,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/mgid/mgidtest/exemplary/simple-banner_no_device_no_site.json b/adapters/mgid/mgidtest/exemplary/simple-banner_no_device_no_site.json index 9849424b49..59cc0da7a6 100644 --- a/adapters/mgid/mgidtest/exemplary/simple-banner_no_device_no_site.json +++ b/adapters/mgid/mgidtest/exemplary/simple-banner_no_device_no_site.json @@ -94,7 +94,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/mgid/mgidtest/exemplary/simple-banner_with_crtype.json b/adapters/mgid/mgidtest/exemplary/simple-banner_with_crtype.json index 586176fb6c..262ae402a4 100644 --- a/adapters/mgid/mgidtest/exemplary/simple-banner_with_crtype.json +++ b/adapters/mgid/mgidtest/exemplary/simple-banner_with_crtype.json @@ -111,7 +111,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/msft/iab_categories.go b/adapters/msft/iab_categories.go new file mode 100644 index 0000000000..4340e4cc6d --- /dev/null +++ b/adapters/msft/iab_categories.go @@ -0,0 +1,106 @@ +package msft + +// findIABCategoryForBid maps a Microsoft brand id to an IAB category. +func findIABCategoryForBid(bid *bidExt) (string, bool) { + iabCategory, ok := iabCategoryMap[bid.Appnexus.BrandCategory] + return iabCategory, ok +} + +// convert to int key. why was it not before? +var iabCategoryMap = map[int]string{ + 1: "IAB20-3", + 2: "IAB18-5", + 3: "IAB10-1", + 4: "IAB2-3", + 5: "IAB19-8", + 6: "IAB22-1", + 7: "IAB18-1", + 8: "IAB12-3", + 9: "IAB5-1", + 10: "IAB4-5", + 11: "IAB13-4", + 12: "IAB8-7", + 13: "IAB9-7", + 14: "IAB7-1", + 15: "IAB20-18", + 16: "IAB10-7", + 17: "IAB19-18", + 18: "IAB13-6", + 19: "IAB18-4", + 20: "IAB1-5", + 21: "IAB1-6", + 22: "IAB3-4", + 23: "IAB19-13", + 24: "IAB22-2", + 25: "IAB3-9", + 26: "IAB17-18", + 27: "IAB19-6", + 28: "IAB1-7", + 29: "IAB9-30", + 30: "IAB20-7", + 31: "IAB20-17", + 32: "IAB7-32", + 33: "IAB16-5", + 34: "IAB19-34", + 35: "IAB11-5", + 36: "IAB12-3", + 37: "IAB11-4", + 38: "IAB12-3", + 39: "IAB9-30", + 41: "IAB7-44", + 42: "IAB7-1", + 43: "IAB7-30", + 50: "IAB19-30", + 51: "IAB17-12", + 52: "IAB19-30", + 53: "IAB3-1", + 55: "IAB13-2", + 56: "IAB19-30", + 57: "IAB19-30", + 58: "IAB7-39", + 59: "IAB22-1", + 60: "IAB7-39", + 61: "IAB21-3", + 62: "IAB5-1", + 63: "IAB12-3", + 64: "IAB20-18", + 65: "IAB11-2", + 66: "IAB17-18", + 67: "IAB9-9", + 68: "IAB9-5", + 69: "IAB7-44", + 71: "IAB22-3", + 73: "IAB19-30", + 74: "IAB8-5", + 78: "IAB22-1", + 85: "IAB12-2", + 86: "IAB22-3", + 87: "IAB11-3", + 112: "IAB7-32", + 113: "IAB7-32", + 114: "IAB7-32", + 115: "IAB7-32", + 118: "IAB9-5", + 119: "IAB9-5", + 120: "IAB9-5", + 121: "IAB9-5", + 122: "IAB9-5", + 123: "IAB9-5", + 124: "IAB9-5", + 125: "IAB9-5", + 126: "IAB9-5", + 127: "IAB22-1", + 132: "IAB1-2", + 133: "IAB19-30", + 137: "IAB3-9", + 138: "IAB19-3", + 140: "IAB2-3", + 141: "IAB2-1", + 142: "IAB2-3", + 143: "IAB17-13", + 166: "IAB11-4", + 175: "IAB3-1", + 176: "IAB13-4", + 182: "IAB8-9", + 183: "IAB3-5", +} diff --git a/adapters/msft/models.go b/adapters/msft/models.go new file mode 100644 index 0000000000..625251c773 --- /dev/null +++ b/adapters/msft/models.go @@ -0,0 +1,60 @@ +package msft + +import ( + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +type extraAdapterInfo struct { + HBSource int `json:"hb_source"` + HBSourceVideo int `json:"hb_source_video"` +} + +// impExtIncoming defines the incoming data contract to Prebid Server. +type impExtIncoming struct { + Bidder openrtb_ext.ImpExtMsft `json:"bidder"` + GPID string `json:"gpid"` +} + +// impExtOutgoing defines the outgoing data contract from Prebid Server to Microsoft. +type impExtOutgoing struct { + Appnexus impExtOutgoingAppnexus `json:"appnexus"` + GPID string `json:"gpid,omitempty"` +} + +type impExtOutgoingAppnexus struct { + PlacementID int `json:"placement_id,omitempty"` + AllowSmallerSizes *bool `json:"allow_smaller_sizes,omitempty"` + UsePmtRule *bool `json:"use_pmt_rule,omitempty"` + Keywords string `json:"keywords,omitempty"` + TrafficSourceCode string `json:"traffic_source_code,omitempty"` + PubClick string `json:"pub_click,omitempty"` + ExtInvCode string `json:"ext_inv_code,omitempty"` + ExtImpID string `json:"ext_imp_id,omitempty"` +} + +type bidExtVideo struct { + Duration int `json:"duration"` +} + +type bidExtCreative struct { + Video bidExtVideo `json:"video"` +} + +type bidExtAppnexus struct { + BidType int `json:"bid_ad_type"` + BrandId int `json:"brand_id"` + BrandCategory int `json:"brand_category_id"` + CreativeInfo bidExtCreative `json:"creative_info"` + DealPriority int `json:"deal_priority"` +} + +type bidExt struct { + Appnexus bidExtAppnexus `json:"appnexus"` +} + +type requestExAppnexus struct { + IncludeBrandCategory *bool `json:"include_brand_category,omitempty"` + BrandCategoryUniqueness *bool `json:"brand_category_uniqueness,omitempty"` + IsAMP int `json:"is_amp,omitempty"` + HeaderBiddingSource int `json:"hb_source,omitempty"` +} diff --git a/adapters/msft/msft.go b/adapters/msft/msft.go new file mode 100644 index 0000000000..c7711dace6 --- /dev/null +++ b/adapters/msft/msft.go @@ -0,0 +1,395 @@ +package msft + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + + "github.com/buger/jsonparser" + "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/metrics" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v3/util/ptrutil" +) + +const ( + defaultHBSource = 5 + defaultHBSourceVideo = 6 + maxImpsPerReq = 10 +) + +var ( + errMalformedExtraInfo = errors.New("malformed extra adapter info") + errMalformedRequestExt = errors.New("malformed request ext.appnexus") + errMemberIDMismatch = errors.New("member id mismatch: all impressions must use the same member id") +) + +type adapter struct { + uri url.URL + hbSource int + hbSourceVideo int +} + +// Builder builds a new instance of the Microsoft adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) { + uri, err := url.Parse(config.Endpoint) + if err != nil { + return nil, err + } + + extraInfo, err := parseExtraInfo(config.ExtraAdapterInfo) + if err != nil { + return nil, err + } + + bidder := &adapter{ + uri: *uri, + hbSource: extraInfo.HBSource, + hbSourceVideo: extraInfo.HBSourceVideo, + } + return bidder, nil +} + +func parseExtraInfo(v string) (extraAdapterInfo, error) { + if len(v) == 0 { + return buildDefaultExtraInfo(), nil + } + + var info extraAdapterInfo + if err := jsonutil.Unmarshal([]byte(v), &info); err != nil { + return info, errMalformedExtraInfo + } + + if info.HBSource == 0 { + info.HBSource = defaultHBSource + } + + if info.HBSourceVideo == 0 { + info.HBSourceVideo = defaultHBSourceVideo + } + + return info, nil +} + +func buildDefaultExtraInfo() extraAdapterInfo { + return extraAdapterInfo{ + HBSource: defaultHBSource, + HBSourceVideo: defaultHBSourceVideo, + } +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + displayManagerVerBuilder := initDisplayManageVerBuilder(request) + + var ( + uniqueMemberID int + errs []error + ) + + validImps := []openrtb2.Imp{} + for i := 0; i < len(request.Imp); i++ { + var impExt impExtIncoming + if err := jsonutil.Unmarshal(request.Imp[i].Ext, &impExt); err != nil { + errs = append(errs, fmt.Errorf("failed to parse ext for impression id '%s'", request.Imp[i].ID)) + continue + } + + if err := modifyImp(&request.Imp[i], impExt, displayManagerVerBuilder); err != nil { + errs = append(errs, fmt.Errorf("failed to build ext for impression id '%s'", request.Imp[i].ID)) + continue + } + + // ensure all impressions with member ids use the same member id + memberID := impExt.Bidder.Member + if memberID != 0 { + if uniqueMemberID == 0 { + uniqueMemberID = memberID + } else if uniqueMemberID != memberID { + errs = append(errs, errMemberIDMismatch) + return nil, errs + } + } + + validImps = append(validImps, request.Imp[i]) + } + + if len(validImps) == 0 { + return nil, errs + } + + request.Imp = validImps + + requestURI := a.uri + if uniqueMemberID != 0 { + requestURI = appendMemberID(requestURI, uniqueMemberID) + } + + if err := a.modifyRequestExt(request, requestInfo); err != nil { + return nil, append(errs, err) + } + + requests, errors := buildRequests(request.Imp, request, requestURI.String()) + return requests, append(errs, errors...) +} + +func initDisplayManageVerBuilder(req *openrtb2.BidRequest) func() string { + if req.App == nil || len(req.App.Ext) == 0 { + return func() string { return "" } + } + + var ( + appExt json.RawMessage = req.App.Ext + result string + hasRun bool + ) + return func() string { + if !hasRun { + source, err := jsonparser.GetString(appExt, openrtb_ext.PrebidExtKey, "source") + if err != nil { + hasRun = true + return result + } + + version, err := jsonparser.GetString(appExt, openrtb_ext.PrebidExtKey, "version") + if err != nil { + hasRun = true + return result + } + + result = fmt.Sprintf("%s-%s", source, version) + hasRun = true + } + return result + } +} + +func modifyImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVerBuilder func() string) error { + if ext.Bidder.InvCode != "" { + imp.TagID = ext.Bidder.InvCode + } + + if imp.Banner != nil { + bannerCopy := *imp.Banner + + if bannerCopy.W == nil && bannerCopy.H == nil && len(bannerCopy.Format) > 0 { + firstFormat := bannerCopy.Format[0] + bannerCopy.W = &(firstFormat.W) + bannerCopy.H = &(firstFormat.H) + } + + if bannerCopy.API == nil { + bannerCopy.API = ext.Bidder.BannerFrameworks + } + + imp.Banner = &bannerCopy + } + + if len(imp.DisplayManagerVer) == 0 { + imp.DisplayManagerVer = displayManagerVerBuilder() + } + + impExt := impExtOutgoing{ + Appnexus: impExtOutgoingAppnexus{ + PlacementID: ext.Bidder.PlacementID, + AllowSmallerSizes: ext.Bidder.AllowSmallerSizes, + UsePmtRule: ext.Bidder.UsePaymentRule, + Keywords: ext.Bidder.Keywords, + TrafficSourceCode: ext.Bidder.TrafficSourceCode, + PubClick: ext.Bidder.PubClick, + ExtInvCode: ext.Bidder.ExtInvCode, + ExtImpID: ext.Bidder.ExtImpID, + }, + GPID: ext.GPID, + } + + var err error + imp.Ext, err = jsonutil.Marshal(impExt) + + return err +} + +func appendMemberID(uri url.URL, memberID int) url.URL { + q := uri.Query() + q.Set("member_id", fmt.Sprint(memberID)) + uri.RawQuery = q.Encode() + return uri +} + +func (a *adapter) modifyRequestExt(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) error { + reqExt, err := getRequestExt(request.Ext) + if err != nil { + return err + } + + reqExtAppnexus, err := a.getAppnexusExt(reqExt, requestInfo.PbsEntryPoint) + if err != nil { + return err + } + + appnexusExtJson, err := jsonutil.Marshal(reqExtAppnexus) + if err != nil { + return err + } + + reqExt["appnexus"] = appnexusExtJson + + request.Ext, err = jsonutil.Marshal(reqExt) + return err +} + +func getRequestExt(ext json.RawMessage) (map[string]json.RawMessage, error) { + extMap := make(map[string]json.RawMessage) + + if len(ext) > 0 { + if err := jsonutil.Unmarshal(ext, &extMap); err != nil { + return nil, err + } + } + + return extMap, nil +} + +func (a *adapter) getAppnexusExt(extMap map[string]json.RawMessage, reqType metrics.RequestType) (requestExAppnexus, error) { + var appnexusExt requestExAppnexus + + if appnexusExtJson, exists := extMap["appnexus"]; exists && len(appnexusExtJson) > 0 { + if err := jsonutil.Unmarshal(appnexusExtJson, &appnexusExt); err != nil { + return appnexusExt, errMalformedRequestExt + } + } + + if prebidJson, exists := extMap["prebid"]; exists { + _, valueType, _, err := jsonparser.Get(prebidJson, "targeting", "includebrandcategory") + if err != nil && !errors.Is(err, jsonparser.KeyPathNotFoundError) { + return appnexusExt, err + } + + if valueType == jsonparser.Object { + appnexusExt.BrandCategoryUniqueness = ptrutil.ToPtr(true) + appnexusExt.IncludeBrandCategory = ptrutil.ToPtr(true) + } + } + + if reqType == metrics.ReqTypeAMP { + appnexusExt.IsAMP = 1 + } + + if reqType == metrics.ReqTypeVideo { + appnexusExt.HeaderBiddingSource = a.hbSourceVideo + } else { + appnexusExt.HeaderBiddingSource = a.hbSource + } + + return appnexusExt, nil +} + +func buildRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, uri string) ([]*adapters.RequestData, []error) { + var ( + requestsCount = (len(imps) + maxImpsPerReq - 1) / maxImpsPerReq + requests = make([]*adapters.RequestData, 0, requestsCount) + ) + + headers := buildHeaders() + + for i := range requestsCount { + impsForRequest := imps[i*maxImpsPerReq : min((i+1)*maxImpsPerReq, len(imps))] + + request.Imp = impsForRequest + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{err} + } + + requests = append(requests, &adapters.RequestData{ + Method: http.MethodPost, + Uri: uri, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }) + } + + return requests, nil +} + +func buildHeaders() http.Header { + headers := http.Header{} + headers.Set("Content-Type", "application/json;charset=utf-8") + headers.Set("Accept", "application/json") + headers.Set("x-openrtb-version", "2.6") + return headers +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var appnexusResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &appnexusResponse); err != nil { + return nil, []error{err} + } + + var errs []error + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(5) + for _, sb := range appnexusResponse.SeatBid { + for i := range sb.Bid { + bid := sb.Bid[i] + + var bidExt bidExt + if err := jsonutil.Unmarshal(bid.Ext, &bidExt); err != nil { + errs = append(errs, err) + continue + } + + bidType, err := getMediaTypeForBid(&bidExt) + if err != nil { + errs = append(errs, err) + continue + } + + if iabCategory, found := findIABCategoryForBid(&bidExt); found { + bid.Cat = []string{iabCategory} + } else if len(bid.Cat) > 1 { + //create empty categories array to force bid to be rejected + bid.Cat = []string{} + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: bidExt.Appnexus.CreativeInfo.Video.Duration}, + DealPriority: bidExt.Appnexus.DealPriority, + }) + } + } + + if appnexusResponse.Cur != "" { + bidderResponse.Currency = appnexusResponse.Cur + } + + return bidderResponse, errs +} + +func getMediaTypeForBid(bid *bidExt) (openrtb_ext.BidType, error) { + switch bid.Appnexus.BidType { + case 0: + return openrtb_ext.BidTypeBanner, nil + case 1: + return openrtb_ext.BidTypeVideo, nil + case 3: + return openrtb_ext.BidTypeNative, nil + default: + return "", fmt.Errorf("unrecognized bid_ad_type in response: %d", bid.Appnexus.BidType) + } +} diff --git a/adapters/msft/msft_test.go b/adapters/msft/msft_test.go new file mode 100644 index 0000000000..b16a8c64b2 --- /dev/null +++ b/adapters/msft/msft_test.go @@ -0,0 +1,77 @@ +package msft + +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/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderMicrosoft, + config.Adapter{Endpoint: "http://any.url"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "test", bidder) +} + +func TestJsonSamplesWithExtraInfo(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderMicrosoft, + config.Adapter{Endpoint: "http://any.url", ExtraAdapterInfo: `{"hb_source": 50, "hb_source_video": 60}`}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "test-extrainfo", bidder) +} + +func TestBadConfig(t *testing.T) { + t.Run("invalid", func(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderMicrosoft, + config.Adapter{ + Endpoint: `http://any.url`, + ExtraAdapterInfo: `malformed`, + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) + }) + + t.Run("empty-value", func(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderMicrosoft, + config.Adapter{ + Endpoint: `http://any.url`, + ExtraAdapterInfo: ``, + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + adapter := bidder.(*adapter) + + assert.NoError(t, buildErr) + assert.Equal(t, adapter.hbSource, defaultHBSource) + assert.Equal(t, adapter.hbSourceVideo, defaultHBSourceVideo) + }) + + t.Run("empty-object", func(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderMicrosoft, + config.Adapter{ + Endpoint: `http://any.url`, + ExtraAdapterInfo: `{}`, + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + adapter := bidder.(*adapter) + + assert.NoError(t, buildErr) + assert.Equal(t, adapter.hbSource, defaultHBSource) + assert.Equal(t, adapter.hbSourceVideo, defaultHBSourceVideo) + }) +} diff --git a/adapters/msft/params_test.go b/adapters/msft/params_test.go new file mode 100644 index 0000000000..1046a4a0b2 --- /dev/null +++ b/adapters/msft/params_test.go @@ -0,0 +1,79 @@ +package msft + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file tests static/bidder-params/msft.json +// +// These validate the format of the external API: request.imp[i].ext.prebid.bidder.msft + +// TestValidParams makes sure that the msft schema accepts all imp.ext fields which we intend to support. +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.BidderMicrosoft, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected msft params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the msft schema rejects all the imp.ext fields we don't support. +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.BidderMicrosoft, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placement_id": 123}`, + `{"member": 123, "inv_code": "test-inv"}`, + `{"placement_id": 123, "allow_smaller_sizes": true}`, + `{"placement_id": 123, "use_pmt_rule": false}`, + `{"placement_id": 123, "keywords": "key1=val1,key2=val2"}`, + `{"placement_id": 123, "traffic_source_code": "test-source"}`, + `{"placement_id": 123, "pubclick": "http://example.com/click"}`, + `{"placement_id": 123, "ext_inv_code": "ext-inv-123"}`, + `{"placement_id": 123, "ext_imp_id": "ext-imp-456"}`, + `{"placement_id": 123, "banner_frameworks": [1, 2, 3]}`, + `{"member": 958, "inv_code": "test-inv-code", "keywords": "genre=rock,age=25"}`, + `{"placement_id": 123, "allow_smaller_sizes": true, "use_pmt_rule": true, "keywords": "key=value", "traffic_source_code": "multi-param-test"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `42`, + `[]`, + `{}`, + `{"member": 123}`, + `{"inv_code": "test"}`, + `{"placement_id": "123"}`, + `{"member": "123", "inv_code": "test"}`, + `{"placement_id": 123, "allow_smaller_sizes": "not-a-boolean"}`, + `{"placement_id": 123, "use_pmt_rule": "not-a-boolean"}`, + `{"placement_id": 123, "keywords": ["not", "a", "string"]}`, + `{"placement_id": 123, "traffic_source_code": 123}`, + `{"placement_id": 123, "pubclick": true}`, + `{"placement_id": 123, "ext_inv_code": 456}`, + `{"placement_id": 123, "ext_imp_id": false}`, + `{"placement_id": 123, "banner_frameworks": "not-array"}`, + `{"placement_id": 123, "banner_frameworks": ["1", "2", 3]}`, + `{"member": 123, "inv_code": 456}`, + `{"placement_id": "string-not-int"}`, +} diff --git a/adapters/msft/test-extrainfo/exemplary/simple-banner.json b/adapters/msft/test-extrainfo/exemplary/simple-banner.json new file mode 100644 index 0000000000..2cf992dce8 --- /dev/null +++ b/adapters/msft/test-extrainfo/exemplary/simple-banner.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 50 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test-extrainfo/video/simple-video.json b/adapters/msft/test-extrainfo/video/simple-video.json new file mode 100644 index 0000000000..4f7527c2b2 --- /dev/null +++ b/adapters/msft/test-extrainfo/video/simple-video.json @@ -0,0 +1,168 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "ext": { + "appnexus": { + "hb_source": 60 + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB9-1" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/amp/simple-banner.json b/adapters/msft/test/amp/simple-banner.json new file mode 100644 index 0000000000..ac02667baa --- /dev/null +++ b/adapters/msft/test/amp/simple-banner.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5, + "is_amp": 1 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/exemplary/all-params.json b/adapters/msft/test/exemplary/all-params.json new file mode 100644 index 0000000000..ea9d9aa57f --- /dev/null +++ b/adapters/msft/test/exemplary/all-params.json @@ -0,0 +1,182 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1, + "member": 958, + "inv_code": "any-inv-code", + "allow_smaller_sizes": true, + "use_pmt_rule": true, + "keywords": "key1=val1,key2=val2", + "traffic_source_code": "any-traffic-source-code", + "pubclick": "http://example.com/click", + "ext_inv_code": "any-ext-inv-code", + "ext_imp_id": "any-ext-imp-id", + "banner_frameworks": [ + 1, + 2, + 3 + ] + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url?member_id=958", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "any-inv-code", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250, + "api": [ + 1, + 2, + 3 + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1, + "allow_smaller_sizes": true, + "use_pmt_rule": true, + "keywords": "key1=val1,key2=val2", + "traffic_source_code": "any-traffic-source-code", + "pub_click": "http://example.com/click", + "ext_inv_code": "any-ext-inv-code", + "ext_imp_id": "any-ext-imp-id" + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/exemplary/simple-banner.json b/adapters/msft/test/exemplary/simple-banner.json new file mode 100644 index 0000000000..dac4ab160d --- /dev/null +++ b/adapters/msft/test/exemplary/simple-banner.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/exemplary/simple-native.json b/adapters/msft/test/exemplary/simple-native.json new file mode 100644 index 0000000000..b5c9fcdaf8 --- /dev/null +++ b/adapters/msft/test/exemplary/simple-native.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}", + "ver": "1.1" + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://any-url.com/some-creative.jpg\",\"w\": 3000,\"h\": 2250,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 3,\"data\":{\"value\":\"Prebid.org\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}}],\"link\":{\"url\":\"http://any-url.com/any-link\"},\"imptrackers\":[\"http://any-url.com/any-tracker\"],\"jstracker\":\"<script src=\\\"http://www.dummyurl.js\\\"></script>\"}", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 3, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://any-url.com/some-creative.jpg\",\"w\": 3000,\"h\": 2250,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 3,\"data\":{\"value\":\"Prebid.org\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}}],\"link\":{\"url\":\"http://any-url.com/any-link\"},\"imptrackers\":[\"http://any-url.com/any-tracker\"],\"jstracker\":\"<script src=\\\"http://www.dummyurl.js\\\"></script>\"}", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 3, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/exemplary/simple-video.json b/adapters/msft/test/exemplary/simple-video.json new file mode 100644 index 0000000000..9e9fb4c2b1 --- /dev/null +++ b/adapters/msft/test/exemplary/simple-video.json @@ -0,0 +1,168 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB9-1" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/banner-api-not-overridden.json b/adapters/msft/test/supplemental/banner-api-not-overridden.json new file mode 100644 index 0000000000..2b168abf3d --- /dev/null +++ b/adapters/msft/test/supplemental/banner-api-not-overridden.json @@ -0,0 +1,170 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "api": [ + 4, + 5, + 6 + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1, + "banner_frameworks": [ + 1, + 2, + 3 + ] + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250, + "api": [ + 4, + 5, + 6 + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/bid-cat-brand-category-override.json b/adapters/msft/test/supplemental/bid-cat-brand-category-override.json new file mode 100644 index 0000000000..d41757a91f --- /dev/null +++ b/adapters/msft/test/supplemental/bid-cat-brand-category-override.json @@ -0,0 +1,156 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 2, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB18-5" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 2, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/bid-cat-multiple.json b/adapters/msft/test/supplemental/bid-cat-multiple.json new file mode 100644 index 0000000000..cc31db1fc9 --- /dev/null +++ b/adapters/msft/test/supplemental/bid-cat-multiple.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB20-3", + "IAB18-5" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "ext": { + "appnexus": { + "brand_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/bid-cat.json b/adapters/msft/test/supplemental/bid-cat.json new file mode 100644 index 0000000000..2abad1b60c --- /dev/null +++ b/adapters/msft/test/supplemental/bid-cat.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/bid-type-invalid.json b/adapters/msft/test/supplemental/bid-type-invalid.json new file mode 100644 index 0000000000..18bc30f535 --- /dev/null +++ b/adapters/msft/test/supplemental/bid-type-invalid.json @@ -0,0 +1,126 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "2", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "3", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "4", + "crid": "5", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 2, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unrecognized bid_ad_type in response: 2", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/displaymanagerver-generated-missing-source.json b/adapters/msft/test/supplemental/displaymanagerver-generated-missing-source.json new file mode 100644 index 0000000000..df1fb70850 --- /dev/null +++ b/adapters/msft/test/supplemental/displaymanagerver-generated-missing-source.json @@ -0,0 +1,163 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "version": "1.0.0" + } + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "version": "1.0.0" + } + } + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/displaymanagerver-generated-missing-version.json b/adapters/msft/test/supplemental/displaymanagerver-generated-missing-version.json new file mode 100644 index 0000000000..2c8d2a8181 --- /dev/null +++ b/adapters/msft/test/supplemental/displaymanagerver-generated-missing-version.json @@ -0,0 +1,163 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile" + } + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile" + } + } + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/displaymanagerver-generated-multiple-imps.json b/adapters/msft/test/supplemental/displaymanagerver-generated-multiple-imps.json new file mode 100644 index 0000000000..aa9e201f37 --- /dev/null +++ b/adapters/msft/test/supplemental/displaymanagerver-generated-multiple-imps.json @@ -0,0 +1,210 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile", + "version": "1.0.0" + } + } + }, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 2 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile", + "version": "1.0.0" + } + } + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "prebid-mobile-1.0.0", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "prebid-mobile-1.0.0", + "ext": { + "appnexus": { + "placement_id": 2 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-1", + "test-imp-id-2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-2", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/displaymanagerver-generated.json b/adapters/msft/test/supplemental/displaymanagerver-generated.json new file mode 100644 index 0000000000..6b7f7de6da --- /dev/null +++ b/adapters/msft/test/supplemental/displaymanagerver-generated.json @@ -0,0 +1,166 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile", + "version": "1.0.0" + } + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": { + "ext": { + "prebid": { + "source": "prebid-mobile", + "version": "1.0.0" + } + } + }, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "prebid-mobile-1.0.0", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/explicit-dimensions.json b/adapters/msft/test/supplemental/explicit-dimensions.json new file mode 100644 index 0000000000..0afe7c6980 --- /dev/null +++ b/adapters/msft/test/supplemental/explicit-dimensions.json @@ -0,0 +1,155 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 100, + "h": 200 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 100, + "h": 200 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/foreign-currency.json b/adapters/msft/test/supplemental/foreign-currency.json new file mode 100644 index 0000000000..c1a13695e8 --- /dev/null +++ b/adapters/msft/test/supplemental/foreign-currency.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "MXN" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "MXN", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/gpid-passthrough.json b/adapters/msft/test/supplemental/gpid-passthrough.json new file mode 100644 index 0000000000..0888d78656 --- /dev/null +++ b/adapters/msft/test/supplemental/gpid-passthrough.json @@ -0,0 +1,155 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + }, + "gpid": "anyGPID" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + }, + "gpid": "anyGPID" + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/imps-none-valid.json b/adapters/msft/test/supplemental/imps-none-valid.json new file mode 100644 index 0000000000..12250af4f0 --- /dev/null +++ b/adapters/msft/test/supplemental/imps-none-valid.json @@ -0,0 +1,55 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version" + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": "invalid" + } + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "failed to parse ext for impression id 'test-imp-id-1'", + "comparison": "literal" + }, + { + "value": "failed to parse ext for impression id 'test-imp-id-2'", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/include-brand-category.json b/adapters/msft/test/supplemental/include-brand-category.json new file mode 100644 index 0000000000..fab8e0ed5c --- /dev/null +++ b/adapters/msft/test/supplemental/include-brand-category.json @@ -0,0 +1,175 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ], + "ext": { + "prebid": { + "targeting": { + "includebrandcategory": { + "primaryadserver": 1, + "publisher": "anyPublisher", + "withcategory": true + } + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5, + "brand_category_uniqueness": true, + "include_brand_category": true + }, + "prebid": { + "targeting": { + "includebrandcategory": { + "primaryadserver": 1, + "publisher": "anyPublisher", + "withcategory": true + } + } + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/inv-code-overridden.json b/adapters/msft/test/supplemental/inv-code-overridden.json new file mode 100644 index 0000000000..1aa68eac38 --- /dev/null +++ b/adapters/msft/test/supplemental/inv-code-overridden.json @@ -0,0 +1,158 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "tagid": "existing-tagid", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1, + "inv_code": "any-inv-code" + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "any-inv-code", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + }, + "gpid": "/1111/homepage#div-1" + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/member-id-conflict.json b/adapters/msft/test/supplemental/member-id-conflict.json new file mode 100644 index 0000000000..23915eafac --- /dev/null +++ b/adapters/msft/test/supplemental/member-id-conflict.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "member": 101, + "inv_code": "abc" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "member": 102, + "inv_code": "abc" + } + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "member id mismatch: all impressions must use the same member id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/member-id.json b/adapters/msft/test/supplemental/member-id.json new file mode 100644 index 0000000000..5fa1fb4755 --- /dev/null +++ b/adapters/msft/test/supplemental/member-id.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "member": 103, + "inv_code": "abc" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url?member_id=103", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "tagid": "abc", + "ext": { + "appnexus": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/multi-bid.json b/adapters/msft/test/supplemental/multi-bid.json new file mode 100644 index 0000000000..6be967d5fe --- /dev/null +++ b/adapters/msft/test/supplemental/multi-bid.json @@ -0,0 +1,211 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid-1", + "adm": "some-test-ad-1", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid-1", + "crid": "any-crid-1", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + { + "id": "bid-2", + "impid": "test-imp-id", + "price": 0.400000, + "adid": "any-adid-2", + "adm": "some-test-ad-2", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid-2", + "crid": "any-crid-2", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad-1", + "adid": "any-adid-1", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid-1", + "crid": "any-crid-1", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-2", + "impid": "test-imp-id", + "price": 0.4, + "adm": "some-test-ad-2", + "adid": "any-adid-2", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid-2", + "crid": "any-crid-2", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/request-ext-appnexus-invalid.json b/adapters/msft/test/supplemental/request-ext-appnexus-invalid.json new file mode 100644 index 0000000000..a814f8ec02 --- /dev/null +++ b/adapters/msft/test/supplemental/request-ext-appnexus-invalid.json @@ -0,0 +1,40 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ], + "ext": { + "appnexus": { + "brand_category_uniqueness": "wrong-format" + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "malformed request ext.appnexus", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/request-ext-appnexus-passthrough.json b/adapters/msft/test/supplemental/request-ext-appnexus-passthrough.json new file mode 100644 index 0000000000..760432eb3d --- /dev/null +++ b/adapters/msft/test/supplemental/request-ext-appnexus-passthrough.json @@ -0,0 +1,159 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ], + "ext": { + "appnexus": { + "brand_category_uniqueness": true + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5, + "brand_category_uniqueness": true + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/request-splitting.json b/adapters/msft/test/supplemental/request-splitting.json new file mode 100644 index 0000000000..a1abded515 --- /dev/null +++ b/adapters/msft/test/supplemental/request-splitting.json @@ -0,0 +1,459 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id-01", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-02", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-03", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-04", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-05", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-06", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-07", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-08", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-09", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-10", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-11", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id-01", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-02", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-03", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-04", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-05", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-06", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-07", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-08", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-09", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + }, + { + "id": "test-imp-id-10", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-01", + "test-imp-id-02", + "test-imp-id-03", + "test-imp-id-04", + "test-imp-id-05", + "test-imp-id-06", + "test-imp-id-07", + "test-imp-id-08", + "test-imp-id-09", + "test-imp-id-10" + ] + }, + "mockResponse": { + "status": 204 + } + }, + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id-11", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id-11" + ] + }, + "mockResponse": { + "status": 204 + } + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/status-400.json b/adapters/msft/test/supplemental/status-400.json new file mode 100644 index 0000000000..932b520a80 --- /dev/null +++ b/adapters/msft/test/supplemental/status-400.json @@ -0,0 +1,83 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/supplemental/unmapped-brand-category.json b/adapters/msft/test/supplemental/unmapped-brand-category.json new file mode 100644 index 0000000000..a3dce7ada7 --- /dev/null +++ b/adapters/msft/test/supplemental/unmapped-brand-category.json @@ -0,0 +1,150 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": {}, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "app": {}, + "ext": { + "appnexus": { + "hb_source": 5 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "displaymanagerver": "any-display-manager-version", + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1000, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1000, + "auction_id": 123456789, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/msft/test/video/simple-video.json b/adapters/msft/test/video/simple-video.json new file mode 100644 index 0000000000..418af77582 --- /dev/null +++ b/adapters/msft/test/video/simple-video.json @@ -0,0 +1,168 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "body": { + "id": "test-request-id", + "site": { + "domain": "any-domain.org", + "page": "any-page" + }, + "ext": { + "appnexus": { + "hb_source": 6 + } + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 15, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6, + 7, + 8 + ], + "w": 940, + "h": 560 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "1", + "bid": [ + { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "any-adid", + "adm": "some-test-ad", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "h": 250, + "w": 300, + "cat": [ + "IAB9-1" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + } + ] + } + ], + "bidid": "any-bidid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "any-adid", + "adomain": [ + "appnexus.com" + ], + "iurl": "http://nym1-ib.adnxs.com/cr?id=101", + "cid": "any-cid", + "crid": "any-crid", + "w": 300, + "h": 250, + "cat": [ + "IAB20-3" + ], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 123456789, + "bid_ad_type": 1, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/oms/omstest/exemplary/simple-banner-cookie-uid.json b/adapters/oms/omstest/exemplary/simple-banner-cookie-uid.json index 047697b48e..029dce45f1 100755 --- a/adapters/oms/omstest/exemplary/simple-banner-cookie-uid.json +++ b/adapters/oms/omstest/exemplary/simple-banner-cookie-uid.json @@ -76,7 +76,7 @@ "status": 200, "body": { "id": "test-request-id", - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/exemplary/simple-banner-multiple-bids.json b/adapters/oms/omstest/exemplary/simple-banner-multiple-bids.json index ce131fa449..50886764ed 100644 --- a/adapters/oms/omstest/exemplary/simple-banner-multiple-bids.json +++ b/adapters/oms/omstest/exemplary/simple-banner-multiple-bids.json @@ -129,7 +129,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/exemplary/simple-banner-uid-with-publisher-id.json b/adapters/oms/omstest/exemplary/simple-banner-uid-with-publisher-id.json index 52e49612ef..359dd06f49 100755 --- a/adapters/oms/omstest/exemplary/simple-banner-uid-with-publisher-id.json +++ b/adapters/oms/omstest/exemplary/simple-banner-uid-with-publisher-id.json @@ -97,7 +97,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/exemplary/simple-banner-uid.json b/adapters/oms/omstest/exemplary/simple-banner-uid.json index 1d748d6af1..59235a252a 100755 --- a/adapters/oms/omstest/exemplary/simple-banner-uid.json +++ b/adapters/oms/omstest/exemplary/simple-banner-uid.json @@ -97,7 +97,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/exemplary/simple-multi-type-banner.json b/adapters/oms/omstest/exemplary/simple-multi-type-banner.json index c6916a52a9..c359abe34a 100644 --- a/adapters/oms/omstest/exemplary/simple-multi-type-banner.json +++ b/adapters/oms/omstest/exemplary/simple-multi-type-banner.json @@ -109,7 +109,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/exemplary/simple-video.json b/adapters/oms/omstest/exemplary/simple-video.json index 619c0ec48c..32f3fa620f 100644 --- a/adapters/oms/omstest/exemplary/simple-video.json +++ b/adapters/oms/omstest/exemplary/simple-video.json @@ -109,7 +109,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/oms/omstest/supplemental/simple-banner-with-ipv6.json b/adapters/oms/omstest/supplemental/simple-banner-with-ipv6.json index 59b87d4346..820740ce04 100755 --- a/adapters/oms/omstest/supplemental/simple-banner-with-ipv6.json +++ b/adapters/oms/omstest/supplemental/simple-banner-with-ipv6.json @@ -90,7 +90,7 @@ "status": 200, "body": { "id": "test-request-id", - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/onetag/onetagtest/exemplary/simple-banner.json b/adapters/onetag/onetagtest/exemplary/simple-banner.json index 0961775782..368ae82361 100644 --- a/adapters/onetag/onetagtest/exemplary/simple-banner.json +++ b/adapters/onetag/onetagtest/exemplary/simple-banner.json @@ -167,9 +167,9 @@ ], "seat": "772" } - ] - }, - "cur": "USD" + ], + "cur": "USD" + } } } ], diff --git a/adapters/orbidder/orbiddertest/exemplary/multibid-multi-format-with-mtype.json b/adapters/orbidder/orbiddertest/exemplary/multibid-multi-format-with-mtype.json index 8cb7e7dde0..0b63ff995e 100644 --- a/adapters/orbidder/orbiddertest/exemplary/multibid-multi-format-with-mtype.json +++ b/adapters/orbidder/orbiddertest/exemplary/multibid-multi-format-with-mtype.json @@ -153,7 +153,7 @@ ], "expectedBidResponses": [ { - "currency": "USD", + "currency": "EUR", "bids": [ { "bid": { diff --git a/adapters/playdigo/playdigotest/exemplary/multi-imp.json b/adapters/playdigo/playdigotest/exemplary/multi-imp.json index 571642d753..88bfbdbbbe 100644 --- a/adapters/playdigo/playdigotest/exemplary/multi-imp.json +++ b/adapters/playdigo/playdigotest/exemplary/multi-imp.json @@ -11,7 +11,7 @@ }, "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -32,7 +32,7 @@ } }, { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -62,7 +62,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -93,7 +93,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-1"] }, "mockResponse": { "status": 200, @@ -104,7 +104,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://server.playdigo.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -134,7 +134,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -165,7 +165,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-2"] }, "mockResponse": { "status": 200, @@ -176,7 +176,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://server.playdigo.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -206,7 +206,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://server.playdigo.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -230,7 +230,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://server.playdigo.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", diff --git a/adapters/pubrise/pubrisetest/exemplary/multi-imp.json b/adapters/pubrise/pubrisetest/exemplary/multi-imp.json index d922113a51..487ca4f49d 100644 --- a/adapters/pubrise/pubrisetest/exemplary/multi-imp.json +++ b/adapters/pubrise/pubrisetest/exemplary/multi-imp.json @@ -11,7 +11,7 @@ }, "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -32,7 +32,7 @@ } }, { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -62,7 +62,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-1", "tagid": "test", "banner": { "format": [ @@ -93,7 +93,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-1"] }, "mockResponse": { "status": 200, @@ -104,7 +104,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://backend.pubrise.ai/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -134,7 +134,7 @@ "id": "test-request-id", "imp": [ { - "id": "test-imp-id", + "id": "test-imp-2", "tagid": "test", "banner": { "format": [ @@ -165,7 +165,7 @@ "ua": "iPad" } }, - "impIDs":["test-imp-id"] + "impIDs":["test-imp-2"] }, "mockResponse": { "status": 200, @@ -176,7 +176,7 @@ "bid": [ { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://backend.pubrise.ai/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -206,7 +206,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-1", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://backend.pubrise.ai/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", @@ -230,7 +230,7 @@ { "bid": { "id": "test_bid_id", - "impid": "test-imp-id", + "impid": "test-imp-2", "price": 0.27543, "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://backend.pubrise.ai/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", "cid": "test_cid", diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json index ad0a10e469..481680ee93 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-app.json @@ -130,7 +130,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json index 2c630bcb9c..60780e0e51 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-defaultCurrency.json @@ -116,7 +116,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json index 2928927f48..37407ae645 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-deviceConfig.json @@ -106,7 +106,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json index 6325affd1e..6f3a02b19e 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-extUser.json @@ -150,7 +150,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json index bc00032bf3..3911207638 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-floorPrice.json @@ -105,7 +105,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json index e7a56d839b..c6dac4728f 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-iPv6.json @@ -118,7 +118,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json index 8ad28053a1..7d0e6dbd08 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nil-device.json @@ -139,7 +139,8 @@ } ] } - ] + ], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json index 3f14239c5b..f050198bd9 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-nosecure.json @@ -103,7 +103,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json index d87f7f68c8..4e90d3ecd2 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-setCurrency.json @@ -104,7 +104,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "EUR" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json index a45cb63eb1..7d21107d70 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner-sitePage.json @@ -103,7 +103,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-banner.json b/adapters/richaudience/richaudiencetest/exemplary/single-banner.json index a45cb63eb1..7d21107d70 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-banner.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-banner.json @@ -103,7 +103,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/exemplary/single-video.json b/adapters/richaudience/richaudiencetest/exemplary/single-video.json index 390b7837d7..862c10765d 100644 --- a/adapters/richaudience/richaudiencetest/exemplary/single-video.json +++ b/adapters/richaudience/richaudiencetest/exemplary/single-video.json @@ -103,7 +103,8 @@ "h": 640, "w": 480 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json b/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json index 6892ab8ad0..8bebdd7db7 100644 --- a/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json +++ b/adapters/richaudience/richaudiencetest/supplemental/bidTypeNotAssigned.json @@ -104,7 +104,8 @@ "h": 250, "w": 300 }] - }] + }], + "cur": "USD" } } } diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json b/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json index b3317ea44e..77625c74f5 100644 --- a/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner-inapp.json @@ -115,7 +115,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "EUR", + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json b/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json index 42489d40fc..96799d2e17 100644 --- a/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner-multiple-bids.json @@ -136,7 +136,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "EUR", + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/showheroes/showheroestest/exemplary/simple-banner.json b/adapters/showheroes/showheroestest/exemplary/simple-banner.json index c0b3dc4a4f..f96202e7f5 100644 --- a/adapters/showheroes/showheroestest/exemplary/simple-banner.json +++ b/adapters/showheroes/showheroestest/exemplary/simple-banner.json @@ -97,7 +97,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "EUR", + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/showheroes/showheroestest/exemplary/simple-video.json b/adapters/showheroes/showheroestest/exemplary/simple-video.json index 65f10ee940..0854337edb 100644 --- a/adapters/showheroes/showheroestest/exemplary/simple-video.json +++ b/adapters/showheroes/showheroestest/exemplary/simple-video.json @@ -89,7 +89,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "EUR", + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json b/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json index 36511514fd..a656889cb2 100644 --- a/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json +++ b/adapters/showheroes/showheroestest/supplemental/invalid-mtype.json @@ -97,7 +97,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "EUR", + "cur": "EUR", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json index 0b1ffe8700..d5f0880c62 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json @@ -86,7 +86,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json index 6219c7d5ed..ccd6ff3ed1 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json @@ -138,7 +138,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json index d9ab70a1d6..61113c8299 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json @@ -122,7 +122,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json index c7f904e524..86f33d35dc 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json @@ -86,7 +86,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json index f4ff473838..9398e5f7f6 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json @@ -86,7 +86,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json index a09ed5c2f4..6e80e11396 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json @@ -95,7 +95,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json index 01b39a4b7a..64e0e591fd 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json @@ -95,7 +95,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json index 8304adb161..3b1b7d57ab 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json @@ -59,7 +59,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json index e238b34faf..b280dd96e9 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json @@ -98,7 +98,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json b/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json index d7d330de57..2a766ab5b1 100644 --- a/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json +++ b/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json @@ -153,7 +153,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json index 2629242b01..2406716e86 100644 --- a/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json +++ b/adapters/thetradedesk/thetradedesktest/supplemental/auction-price-macro-replacement.json @@ -86,7 +86,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json index 077587438b..432701a111 100644 --- a/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json +++ b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json @@ -48,7 +48,7 @@ "mockResponse": { "status": 200, "body": { - "currency": "USD", + "cur": "USD", "seatbid": [ { "bid": [ diff --git a/adapters/yieldmo/yieldmotest/exemplary/app-banner.json b/adapters/yieldmo/yieldmotest/exemplary/app-banner.json index 7ff5f0de8d..f5353187f1 100644 --- a/adapters/yieldmo/yieldmotest/exemplary/app-banner.json +++ b/adapters/yieldmo/yieldmotest/exemplary/app-banner.json @@ -82,7 +82,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/yieldmo/yieldmotest/exemplary/app_video.json b/adapters/yieldmo/yieldmotest/exemplary/app_video.json index 040906e771..7308e4b370 100644 --- a/adapters/yieldmo/yieldmotest/exemplary/app_video.json +++ b/adapters/yieldmo/yieldmotest/exemplary/app_video.json @@ -80,7 +80,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/yieldmo/yieldmotest/exemplary/simple-banner.json b/adapters/yieldmo/yieldmotest/exemplary/simple-banner.json index 9a5028db04..7a55388067 100644 --- a/adapters/yieldmo/yieldmotest/exemplary/simple-banner.json +++ b/adapters/yieldmo/yieldmotest/exemplary/simple-banner.json @@ -100,7 +100,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/yieldmo/yieldmotest/exemplary/simple_video.json b/adapters/yieldmo/yieldmotest/exemplary/simple_video.json index 010b35a147..5d976322fb 100644 --- a/adapters/yieldmo/yieldmotest/exemplary/simple_video.json +++ b/adapters/yieldmo/yieldmotest/exemplary/simple_video.json @@ -80,7 +80,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/adapters/yieldmo/yieldmotest/exemplary/with_gpid.json b/adapters/yieldmo/yieldmotest/exemplary/with_gpid.json index 12785c7fdb..0f449b87ff 100644 --- a/adapters/yieldmo/yieldmotest/exemplary/with_gpid.json +++ b/adapters/yieldmo/yieldmotest/exemplary/with_gpid.json @@ -90,7 +90,7 @@ ], "expectedBidResponses": [ { - "currency": "EUR", + "currency": "USD", "bids": [ { "bid": { diff --git a/config/adapter.go b/config/adapter.go index 6a6a5fbef7..c629edc16c 100644 --- a/config/adapter.go +++ b/config/adapter.go @@ -7,7 +7,9 @@ type Adapter struct { // needed for Rubicon XAPI AdapterXAPI - // needed for Facebook + // needed for AppNexus and Facebook PlatformID string - AppSecret string + + // nededed for Facebook + AppSecret string } diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 4533be19f9..e6bba140a5 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -167,6 +167,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/mobilefuse" "github.com/prebid/prebid-server/v3/adapters/mobkoi" "github.com/prebid/prebid-server/v3/adapters/motorik" + "github.com/prebid/prebid-server/v3/adapters/msft" "github.com/prebid/prebid-server/v3/adapters/nativery" "github.com/prebid/prebid-server/v3/adapters/nativo" "github.com/prebid/prebid-server/v3/adapters/nextmillennium" @@ -433,6 +434,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderMetaX: metax.Builder, openrtb_ext.BidderMgid: mgid.Builder, openrtb_ext.BidderMgidX: mgidX.Builder, + openrtb_ext.BidderMicrosoft: msft.Builder, openrtb_ext.BidderMinuteMedia: minutemedia.Builder, openrtb_ext.BidderMissena: missena.Builder, openrtb_ext.BidderMobfoxpb: mobfoxpb.Builder, diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index cb214e8994..0a41e6ac0f 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -73,7 +73,7 @@ func TestNewExchange(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -123,7 +123,7 @@ func TestCharacterEscape(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -1229,7 +1229,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) pbc := pbc.NewClient(&http.Client{}, &cfg.CacheURL, &cfg.ExtCacheURL, testEngine) @@ -1588,7 +1588,7 @@ func TestBidResponseCurrency(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -1744,7 +1744,7 @@ func TestBidResponseImpExtInfo(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, nil, gdprPermsBuilder, nil, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange) @@ -1820,7 +1820,7 @@ func TestRaceIntegration(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -1928,7 +1928,7 @@ func TestPanicRecovery(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(&http.Client{}, cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -1994,7 +1994,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) @@ -4571,7 +4571,7 @@ func TestPassExperimentConfigsToHoldAuction(t *testing.T) { adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{}) if adaptersErr != nil { - t.Fatalf("Error intializing adapters: %v", adaptersErr) + t.Fatalf("Error initializing adapters: %v", adaptersErr) } currencyConverter := currency.NewRateConverter(&http.Client{}, time.Duration(1), "", time.Duration(0)) diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 7ccc446d79..82a6df4f77 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -179,6 +179,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderMetaX, BidderMgid, BidderMgidX, + BidderMicrosoft, BidderMinuteMedia, BidderMissena, BidderMobfoxpb, @@ -555,6 +556,7 @@ const ( BidderMetaX BidderName = "metax" BidderMgid BidderName = "mgid" BidderMgidX BidderName = "mgidX" + BidderMicrosoft BidderName = "msft" BidderMinuteMedia BidderName = "minutemedia" BidderMissena BidderName = "missena" BidderMobfoxpb BidderName = "mobfoxpb" diff --git a/openrtb_ext/imp_msft.go b/openrtb_ext/imp_msft.go new file mode 100644 index 0000000000..80e4cb8eee --- /dev/null +++ b/openrtb_ext/imp_msft.go @@ -0,0 +1,18 @@ +package openrtb_ext + +import "github.com/prebid/openrtb/v20/adcom1" + +// ImpExtMsft defines the contract for Microsoft bidder parameters. +type ImpExtMsft struct { + PlacementID int `json:"placement_id"` + Member int `json:"member"` + InvCode string `json:"inv_code"` + AllowSmallerSizes *bool `json:"allow_smaller_sizes"` + UsePaymentRule *bool `json:"use_pmt_rule"` + Keywords string `json:"keywords"` + TrafficSourceCode string `json:"traffic_source_code"` + PubClick string `json:"pubclick"` + ExtInvCode string `json:"ext_inv_code"` + ExtImpID string `json:"ext_imp_id"` + BannerFrameworks []adcom1.APIFramework `json:"banner_frameworks"` +} diff --git a/static/bidder-info/msft.yaml b/static/bidder-info/msft.yaml new file mode 100644 index 0000000000..7511ce39ff --- /dev/null +++ b/static/bidder-info/msft.yaml @@ -0,0 +1,23 @@ +endpoint: "http://ib.adnxs.com/openrtb2" +platform_id: "5" +maintainer: + email: "prebid@microsoft.com" +gvlVendorID: 32 +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + key: "adnxs" + redirect: + url: "https://ib.adnxs.com/getuid?{{.RedirectURL}}" + userMacro: "$UID" diff --git a/static/bidder-params/msft.json b/static/bidder-params/msft.json new file mode 100644 index 0000000000..36894a5295 --- /dev/null +++ b/static/bidder-params/msft.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Microsoft Adapter Params", + "description": "A schema which validates params accepted by the Microsoft adapter", + "type": "object", + "properties": { + "placement_id": { + "type": "integer", + "description": "Placement ID from Microsoft Monetize. You may use inv_code with member instead of a placement_id." + }, + "member": { + "type": "integer", + "description": "Member ID from Microsoft Monetize. Must be used with inv_code." + }, + "inv_code": { + "type": "string", + "description": "Inventory code from Microsoft Monetize. Must be used with member." + }, + "allow_smaller_sizes": { + "type": "boolean", + "description": "If true, ads smaller than your ad unit's size array will be allowed to serve." + }, + "use_pmt_rule": { + "type": "boolean", + "description": "If true, Microsoft Monetize will return net price after publisher payment rules are applied." + }, + "keywords": { + "type": "string", + "description": "Comma-delimited key-value pairs (max 100). Must be enabled by a Microsoft Monetize account manager." + }, + "traffic_source_code": { + "type": "string", + "description": "Specifies the third-party source of this impression." + }, + "pubclick": { + "type": "string", + "description": "Specifies a publisher supplied url for third-party click tracking." + }, + "ext_inv_code": { + "type": "string", + "description": "Specifies predefined value passed on the query string that can be used in reporting. The value must be entered into Microsoft Monetize before it is logged.." + }, + "ext_imp_id": { + "type": "string", + "description": "Specifies the unique identifier of an externally generated auction." + }, + "banner_frameworks": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "List of supported API frameworks for banner ads supported by the publisher." + } + }, + "oneOf": [ + { + "required": [ + "placement_id" + ] + }, + { + "required": [ + "inv_code", + "member" + ] + } + ] +} \ No newline at end of file From e64cf6275f347ba55a39effbd11679abd4e956a6 Mon Sep 17 00:00:00 2001 From: Scott Kay <noreply@syntaxnode.com> Date: Mon, 8 Dec 2025 16:42:19 -0500 Subject: [PATCH 131/272] Syncer: Allow Duplicate Syncer Key For Identical Config (#4622) --- config/bidderinfo.go | 50 +++ config/bidderinfo_test.go | 439 ++++++++++++++++++++++++ usersync/syncersbuilder.go | 18 +- usersync/syncersbuilder_test.go | 35 +- util/ptrutil/ptrutil.go | 12 + util/ptrutil/ptrutil_test.go | 100 ++++++ util/sliceutil/equalignoreorder.go | 26 ++ util/sliceutil/equalignoreorder_test.go | 233 +++++++++++++ 8 files changed, 900 insertions(+), 13 deletions(-) create mode 100644 util/sliceutil/equalignoreorder.go create mode 100644 util/sliceutil/equalignoreorder_test.go diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 8e873cbd04..1f4041ec95 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -11,6 +11,8 @@ import ( "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v3/util/sliceutil" validator "github.com/asaskevich/govalidator" "gopkg.in/yaml.v3" @@ -138,11 +140,44 @@ type Syncer struct { SkipWhen *SkipWhen `yaml:"skipwhen" mapstructure:"skipwhen"` } +func (s *Syncer) Equal(other *Syncer) bool { + if s == nil && other == nil { + return true + } + + if s == nil || other == nil { + return false + } + + return s.Key == other.Key && + sliceutil.EqualIgnoreOrder(s.Supports, other.Supports) && + s.IFrame.Equal(other.IFrame) && + s.Redirect.Equal(other.Redirect) && + s.ExternalURL == other.ExternalURL && + ptrutil.Equal(s.SupportCORS, other.SupportCORS) && + s.FormatOverride == other.FormatOverride && + ptrutil.Equal(s.Enabled, other.Enabled) && + s.SkipWhen.Equal(other.SkipWhen) +} + type SkipWhen struct { GDPR bool `yaml:"gdpr" mapstructure:"gdpr"` GPPSID []string `yaml:"gpp_sid" mapstructure:"gpp_sid"` } +func (s *SkipWhen) Equal(other *SkipWhen) bool { + if s == nil && other == nil { + return true + } + + if s == nil || other == nil { + return false + } + + return s.GDPR == other.GDPR && + sliceutil.EqualIgnoreOrder(s.GPPSID, other.GPPSID) +} + // SyncerEndpoint specifies the configuration of the URL returned by the /cookie_sync endpoint // for a specific bidder. Bidders must specify at least one endpoint configuration to be eligible // for selection during a user sync request. @@ -200,6 +235,21 @@ type SyncerEndpoint struct { UserMacro string `yaml:"userMacro" mapstructure:"user_macro"` } +func (s *SyncerEndpoint) Equal(other *SyncerEndpoint) bool { + if s == nil && other == nil { + return true + } + + if s == nil || other == nil { + return false + } + + return s.URL == other.URL && + s.RedirectURL == other.RedirectURL && + s.ExternalURL == other.ExternalURL && + s.UserMacro == other.UserMacro +} + func (bi BidderInfo) IsEnabled() bool { return !bi.WhiteLabelOnly && !bi.Disabled } diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 41f9687850..8c251842c7 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -1598,6 +1598,445 @@ func TestBidderInfoIsEnabled(t *testing.T) { } } +func TestSyncerEqual(t *testing.T) { + testCases := []struct { + name string + syncer1 *Syncer + syncer2 *Syncer + expected bool + }{ + { + name: "nil", + syncer1: nil, + syncer2: nil, + expected: true, + }, + { + name: "nil-syncer1", + syncer1: nil, + syncer2: &Syncer{Key: "anyKey"}, + expected: false, + }, + { + name: "nil-syncer2", + syncer1: &Syncer{Key: "anyKey"}, + syncer2: nil, + expected: false, + }, + { + name: "different-key", + syncer1: &Syncer{ + Key: "key1", + ExternalURL: "https://example.com", + }, + syncer2: &Syncer{ + Key: "key2", + ExternalURL: "https://example.com", + }, + expected: false, + }, + { + name: "different-external-url", + syncer1: &Syncer{ + Key: "key", + ExternalURL: "https://example1.com", + }, + syncer2: &Syncer{ + Key: "key", + ExternalURL: "https://example2.com", + }, + expected: false, + }, + { + name: "same-supports-nil-vs-empty", + syncer1: &Syncer{ + Key: "key", + Supports: nil, + }, + syncer2: &Syncer{ + Key: "key", + Supports: []string{}, + }, + expected: true, + }, + { + name: "different-supports-ordered", + syncer1: &Syncer{ + Key: "key", + Supports: []string{"iframe"}, + }, + syncer2: &Syncer{ + Key: "key", + Supports: []string{"redirect"}, + }, + expected: false, + }, + { + name: "different-supports-unordered", + syncer1: &Syncer{ + Key: "key", + Supports: []string{"iframe", "redirect"}, + }, + syncer2: &Syncer{ + Key: "key", + Supports: []string{"redirect", "iframe"}, + }, + expected: true, + }, + { + name: "different-iframe-endpoints", + syncer1: &Syncer{ + Key: "key", + IFrame: &SyncerEndpoint{ + URL: "https://iframe1.com", + }, + }, + syncer2: &Syncer{ + Key: "key", + IFrame: &SyncerEndpoint{ + URL: "https://iframe2.com", + }, + }, + expected: false, + }, + { + name: "different-redirect-endpoints", + syncer1: &Syncer{ + Key: "key", + Redirect: &SyncerEndpoint{ + URL: "https://redirect1.com", + }, + }, + syncer2: &Syncer{ + Key: "key", + Redirect: &SyncerEndpoint{ + URL: "https://redirect2.com", + }, + }, + expected: false, + }, + { + name: "different-support-cors", + syncer1: &Syncer{ + Key: "key", + SupportCORS: ptrutil.ToPtr(true), + }, + syncer2: &Syncer{ + Key: "key", + SupportCORS: ptrutil.ToPtr(false), + }, + expected: false, + }, + { + name: "different-format-override", + syncer1: &Syncer{ + Key: "key", + FormatOverride: "i", + }, + syncer2: &Syncer{ + Key: "key", + FormatOverride: "b", + }, + expected: false, + }, + { + name: "different-enabled", + syncer1: &Syncer{ + Key: "key", + Enabled: ptrutil.ToPtr(true), + }, + syncer2: &Syncer{ + Key: "key", + Enabled: ptrutil.ToPtr(false), + }, + expected: false, + }, + { + name: "different-skip-when", + syncer1: &Syncer{ + Key: "key", + SkipWhen: &SkipWhen{ + GDPR: true, + }, + }, + syncer2: &Syncer{ + Key: "key", + SkipWhen: &SkipWhen{ + GDPR: false, + }, + }, + expected: false, + }, + { + name: "same-complete", + syncer1: &Syncer{ + Key: "key", + Supports: []string{"iframe", "redirect"}, + IFrame: &SyncerEndpoint{ + URL: "https://iframe.com", + RedirectURL: "https://redirect.com", + UserMacro: "$UID", + }, + Redirect: &SyncerEndpoint{ + URL: "https://redirect.com", + UserMacro: "$UID", + }, + ExternalURL: "https://external.com", + SupportCORS: ptrutil.ToPtr(true), + FormatOverride: "i", + Enabled: ptrutil.ToPtr(true), + SkipWhen: &SkipWhen{ + GDPR: true, + GPPSID: []string{"1", "2"}, + }, + }, + syncer2: &Syncer{ + Key: "key", + Supports: []string{"redirect", "iframe"}, + IFrame: &SyncerEndpoint{ + URL: "https://iframe.com", + RedirectURL: "https://redirect.com", + UserMacro: "$UID", + }, + Redirect: &SyncerEndpoint{ + URL: "https://redirect.com", + UserMacro: "$UID", + }, + ExternalURL: "https://external.com", + SupportCORS: ptrutil.ToPtr(true), + FormatOverride: "i", + Enabled: ptrutil.ToPtr(true), + SkipWhen: &SkipWhen{ + GDPR: true, + GPPSID: []string{"2", "1"}, + }, + }, + expected: true, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := test.syncer1.Equal(test.syncer2) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestSkipWhenEqual(t *testing.T) { + testCases := []struct { + name string + skipWhen1 *SkipWhen + skipWhen2 *SkipWhen + expected bool + }{ + { + name: "nil", + skipWhen1: nil, + skipWhen2: nil, + expected: true, + }, + { + name: "nil-skipWhen1", + skipWhen1: nil, + skipWhen2: &SkipWhen{GDPR: true, GPPSID: []string{"1"}}, + expected: false, + }, + { + name: "nil-skipWhen2", + skipWhen1: &SkipWhen{GDPR: true, GPPSID: []string{"1"}}, + skipWhen2: nil, + expected: false, + }, + { + name: "empty", + skipWhen1: &SkipWhen{GDPR: false, GPPSID: []string{}}, + skipWhen2: &SkipWhen{GDPR: false, GPPSID: []string{}}, + expected: true, + }, + { + name: "same", + skipWhen1: &SkipWhen{GDPR: true, GPPSID: []string{"1", "2"}}, + skipWhen2: &SkipWhen{GDPR: true, GPPSID: []string{"1", "2"}}, + expected: true, + }, + { + name: "different-gdpr", + skipWhen1: &SkipWhen{GDPR: true, GPPSID: []string{"1", "2"}}, + skipWhen2: &SkipWhen{GDPR: false, GPPSID: []string{"1", "2"}}, + expected: false, + }, + { + name: "different-gppsid", + skipWhen1: &SkipWhen{GDPR: true, GPPSID: []string{"1", "2"}}, + skipWhen2: &SkipWhen{GDPR: true, GPPSID: []string{"1", "3"}}, + expected: false, + }, + { + name: "same-gppsid-unordered", + skipWhen1: &SkipWhen{GDPR: true, GPPSID: []string{"1", "2"}}, + skipWhen2: &SkipWhen{GDPR: true, GPPSID: []string{"2", "1"}}, + expected: true, + }, + { + name: "nil-vs-empty-slice", + skipWhen1: &SkipWhen{GDPR: false, GPPSID: nil}, + skipWhen2: &SkipWhen{GDPR: false, GPPSID: []string{}}, + expected: true, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := test.skipWhen1.Equal(test.skipWhen2) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestSyncerEndpointEqual(t *testing.T) { + testCases := []struct { + name string + endpoint1 *SyncerEndpoint + endpoint2 *SyncerEndpoint + expected bool + }{ + { + name: "nil", + endpoint1: nil, + endpoint2: nil, + expected: true, + }, + { + name: "nil-endpoint1", + endpoint1: nil, + endpoint2: &SyncerEndpoint{URL: "https://example.com"}, + expected: false, + }, + { + name: "nil-endpoint2", + endpoint1: &SyncerEndpoint{URL: "https://example.com"}, + endpoint2: nil, + expected: false, + }, + { + name: "empty", + endpoint1: &SyncerEndpoint{ + URL: "", + RedirectURL: "", + ExternalURL: "", + UserMacro: "", + }, + endpoint2: &SyncerEndpoint{ + URL: "", + RedirectURL: "", + ExternalURL: "", + UserMacro: "", + }, + expected: true, + }, + { + name: "same", + endpoint1: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + expected: true, + }, + { + name: "different-url", + endpoint1: &SyncerEndpoint{ + URL: "https://sync1.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync2.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + expected: false, + }, + { + name: "different-redirect-url", + endpoint1: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host1.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host2.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + expected: false, + }, + { + name: "different-external-url", + endpoint1: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host1.example.com", + UserMacro: "$UID", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host2.example.com", + UserMacro: "$UID", + }, + expected: false, + }, + { + name: "different-user-macro", + endpoint1: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$UID", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync.example.com/iframe", + RedirectURL: "https://host.example.com/setuid", + ExternalURL: "https://host.example.com", + UserMacro: "$USER_ID", + }, + expected: false, + }, + { + name: "different-user-macro-case-sensitive", + endpoint1: &SyncerEndpoint{ + URL: "https://sync.example.com", + UserMacro: "$uid", + }, + endpoint2: &SyncerEndpoint{ + URL: "https://sync.example.com", + UserMacro: "$UID", + }, + expected: false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := test.endpoint1.Equal(test.endpoint2) + assert.Equal(t, test.expected, result) + }) + } +} + func TestSyncerDefined(t *testing.T) { testCases := []struct { name string diff --git a/usersync/syncersbuilder.go b/usersync/syncersbuilder.go index 1127989e9d..2868a1da7d 100644 --- a/usersync/syncersbuilder.go +++ b/usersync/syncersbuilder.go @@ -76,6 +76,7 @@ func BuildSyncers(hostConfig *config.Configuration, bidderInfos config.BidderInf if len(errs) > 0 { return nil, errs } + return syncers, nil } @@ -97,10 +98,13 @@ func chooseSyncerConfig(biddersSyncerConfig []namedSyncerConfig) (namedSyncerCon var bidderNames []string var bidderNamesWithEndpoints []string var syncerConfig namedSyncerConfig + var syncerConfigWithEndpoints []namedSyncerConfig + for _, bidder := range biddersSyncerConfig { bidderNames = append(bidderNames, bidder.name) if bidder.cfg.IFrame != nil || bidder.cfg.Redirect != nil { bidderNamesWithEndpoints = append(bidderNamesWithEndpoints, bidder.name) + syncerConfigWithEndpoints = append(syncerConfigWithEndpoints, bidder) syncerConfig = bidder } } @@ -111,10 +115,16 @@ func chooseSyncerConfig(biddersSyncerConfig []namedSyncerConfig) (namedSyncerCon return namedSyncerConfig{}, fmt.Errorf("bidders %s share the same syncer key, but none define endpoints (iframe and/or redirect)", bidders) } - if len(bidderNamesWithEndpoints) > 1 { - sort.Strings(bidderNamesWithEndpoints) - bidders := strings.Join(bidderNamesWithEndpoints, ", ") - return namedSyncerConfig{}, fmt.Errorf("bidders %s define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints", bidders) + if len(syncerConfigWithEndpoints) > 1 { + // allowed if all configs are identical + firstConfig := syncerConfigWithEndpoints[0].cfg + for _, config := range syncerConfigWithEndpoints[1:] { + if !firstConfig.Equal(&config.cfg) { + sort.Strings(bidderNamesWithEndpoints) + bidders := strings.Join(bidderNamesWithEndpoints, ", ") + return namedSyncerConfig{}, fmt.Errorf("bidders %s define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints unless the configs are identical", bidders) + } + } } return syncerConfig, nil diff --git a/usersync/syncersbuilder_test.go b/usersync/syncersbuilder_test.go index d7026543f4..a08df08172 100644 --- a/usersync/syncersbuilder_test.go +++ b/usersync/syncersbuilder_test.go @@ -22,8 +22,10 @@ func TestBuildSyncers(t *testing.T) { var ( hostConfig = config.Configuration{ExternalURL: "http://host.com", UserSync: config.UserSync{RedirectURL: "{{.ExternalURL}}/{{.SyncerKey}}/host"}} iframeConfig = &config.SyncerEndpoint{URL: "https://bidder.com/iframe?redirect={{.RedirectURL}}"} + iframeConfigAlt = &config.SyncerEndpoint{URL: "https://bidder.com/iframe-alt?redirect={{.RedirectURL}}"} iframeConfigError = &config.SyncerEndpoint{URL: "https://bidder.com/iframe?redirect={{xRedirectURL}}"} // Error caused by invalid macro infoKeyAPopulated = config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfig}} + infoKeyAPopulatedAlt = config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfigAlt}} infoKeyADisabled = config.BidderInfo{Disabled: true, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfig}} infoKeyAEmpty = config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "a"}} infoKeyAError = config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfigError}} @@ -86,11 +88,20 @@ func TestBuildSyncers(t *testing.T) { }, }, { - description: "Many - Same Syncers - Many Primaries", + description: "Many - Same Syncers - Many Primaries - Identical", givenConfig: hostConfig, givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated, "bidder2": infoKeyAPopulated}, + expectedIFramesURLs: map[string]string{ + "bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder1%2Fhost", + "bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost", + }, + }, + { + description: "Many - Same Syncers - Many Primaries - Different", + givenConfig: hostConfig, + givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated, "bidder2": infoKeyAPopulatedAlt}, expectedErrors: []string{ - "bidders bidder1, bidder2 define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints", + "bidders bidder1, bidder2 define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints unless the configs are identical", }, }, { @@ -294,10 +305,11 @@ func TestShouldCreateSyncer(t *testing.T) { func TestChooseSyncerConfig(t *testing.T) { var ( - bidderAPopulated = namedSyncerConfig{name: "bidderA", cfg: config.Syncer{Key: "a", IFrame: &config.SyncerEndpoint{URL: "anyURL"}}} - bidderAEmpty = namedSyncerConfig{name: "bidderA", cfg: config.Syncer{}} - bidderBPopulated = namedSyncerConfig{name: "bidderB", cfg: config.Syncer{Key: "a", IFrame: &config.SyncerEndpoint{URL: "anyURL"}}} - bidderBEmpty = namedSyncerConfig{name: "bidderB", cfg: config.Syncer{}} + bidderAPopulated = namedSyncerConfig{name: "bidderA", cfg: config.Syncer{Key: "a", IFrame: &config.SyncerEndpoint{URL: "anyURL"}}} + bidderAEmpty = namedSyncerConfig{name: "bidderA", cfg: config.Syncer{}} + bidderBPopulated = namedSyncerConfig{name: "bidderB", cfg: config.Syncer{Key: "a", IFrame: &config.SyncerEndpoint{URL: "anyURL"}}} + bidderBPopulatedAlt = namedSyncerConfig{name: "bidderB", cfg: config.Syncer{Key: "a", IFrame: &config.SyncerEndpoint{URL: "differentURL"}}} + bidderBEmpty = namedSyncerConfig{name: "bidderB", cfg: config.Syncer{}} ) testCases := []struct { @@ -317,9 +329,14 @@ func TestChooseSyncerConfig(t *testing.T) { expectedConfig: bidderBPopulated, }, { - description: "Many - Same Key - Multiple Configs", - given: []namedSyncerConfig{bidderAPopulated, bidderBPopulated}, - expectedError: "bidders bidderA, bidderB define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints", + description: "Many - Same Key - Multiple - Same Configs", + given: []namedSyncerConfig{bidderAPopulated, bidderBPopulated}, + expectedConfig: bidderBPopulated, + }, + { + description: "Many - Same Key - Multiple - Different Configs", + given: []namedSyncerConfig{bidderAPopulated, bidderBPopulatedAlt}, + expectedError: "bidders bidderA, bidderB define endpoints (iframe and/or redirect) for the same syncer key, but only one bidder is permitted to define endpoints unless the configs are identical", }, { description: "Many - Same Key - No Configs", diff --git a/util/ptrutil/ptrutil.go b/util/ptrutil/ptrutil.go index 27616a0a4b..c700e6de82 100644 --- a/util/ptrutil/ptrutil.go +++ b/util/ptrutil/ptrutil.go @@ -21,3 +21,15 @@ func ValueOrDefault[T any](v *T) T { var def T return def } + +func Equal[T comparable](v1, v2 *T) bool { + if v1 == nil && v2 == nil { + return true + } + + if v1 == nil || v2 == nil { + return false + } + + return *v1 == *v2 +} diff --git a/util/ptrutil/ptrutil_test.go b/util/ptrutil/ptrutil_test.go index 85671e31b4..028939eb35 100644 --- a/util/ptrutil/ptrutil_test.go +++ b/util/ptrutil/ptrutil_test.go @@ -43,3 +43,103 @@ func TestValueOrDefault(t *testing.T) { assert.Equal(t, "something", r) }) } + +func TestEqualInt(t *testing.T) { + tests := []struct { + name string + value1 *int + value2 *int + expected bool + }{ + { + name: "nil", + value1: nil, + value2: nil, + expected: true, + }, + { + name: "nil-value1", + value1: nil, + value2: ToPtr(42), + expected: false, + }, + { + name: "nil-value2", + value1: ToPtr(42), + value2: nil, + expected: false, + }, + { + name: "same", + value1: ToPtr(42), + value2: ToPtr(42), + expected: true, + }, + { + name: "different", + value1: ToPtr(42), + value2: ToPtr(24), + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := Equal(tt.value1, tt.value2) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestEqualString(t *testing.T) { + tests := []struct { + name string + value1 *string + value2 *string + expected bool + }{ + { + name: "nil", + value1: nil, + value2: nil, + expected: true, + }, + { + name: "nil-value1", + value1: nil, + value2: ToPtr("hello"), + expected: false, + }, + { + name: "nil-value2", + value1: ToPtr("hello"), + value2: nil, + expected: false, + }, + { + name: "same", + value1: ToPtr("hello"), + value2: ToPtr("hello"), + expected: true, + }, + { + name: "different", + value1: ToPtr("hello"), + value2: ToPtr("world"), + expected: false, + }, + { + name: "empty", + value1: ToPtr(""), + value2: ToPtr(""), + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := Equal(tt.value1, tt.value2) + assert.Equal(t, tt.expected, result) + }) + } +} diff --git a/util/sliceutil/equalignoreorder.go b/util/sliceutil/equalignoreorder.go new file mode 100644 index 0000000000..0322af6593 --- /dev/null +++ b/util/sliceutil/equalignoreorder.go @@ -0,0 +1,26 @@ +package sliceutil + +import ( + "maps" +) + +// EqualIgnoreOrder checks if two slices contain the same elements, regardless of their order. This +// is not optimized for memory usage and is intended for use at startup only. Empty and nil slices +// are considered equal, matching slices.Equal behavior. +func EqualIgnoreOrder[T comparable](s1, s2 []T) bool { + if len(s1) != len(s2) { + return false + } + + counts1 := make(map[T]int, len(s1)) + for _, item := range s1 { + counts1[item]++ + } + + counts2 := make(map[T]int, len(s2)) + for _, item := range s2 { + counts2[item]++ + } + + return maps.Equal(counts1, counts2) +} diff --git a/util/sliceutil/equalignoreorder_test.go b/util/sliceutil/equalignoreorder_test.go new file mode 100644 index 0000000000..f6db241ad9 --- /dev/null +++ b/util/sliceutil/equalignoreorder_test.go @@ -0,0 +1,233 @@ +package sliceutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEqualIgnoreOrderInt(t *testing.T) { + tests := []struct { + name string + slice1 []int + slice2 []int + expected bool + }{ + { + name: "nil-both", + slice1: nil, + slice2: nil, + expected: true, + }, + { + name: "nil-s1", + slice1: nil, + slice2: []int{1}, + expected: false, + }, + { + name: "nil-s2", + slice1: []int{1}, + slice2: nil, + expected: false, + }, + { + name: "empty-both", + slice1: []int{}, + slice2: []int{}, + expected: true, + }, + { + name: "empty-s1", + slice1: []int{}, + slice2: []int{1}, + expected: false, + }, + { + name: "empty-s2", + slice1: []int{1}, + slice2: []int{}, + expected: false, + }, + { + name: "nil-empty-mix-1", + slice1: nil, + slice2: []int{}, + expected: true, + }, + { + name: "nil-empty-mix-2", + slice1: []int{}, + slice2: nil, + expected: true, + }, + { + name: "one-same", + slice1: []int{1}, + slice2: []int{1}, + expected: true, + }, + { + name: "one-different", + slice1: []int{1}, + slice2: []int{2}, + expected: false, + }, + { + name: "many-same-ordered", + slice1: []int{1, 2}, + slice2: []int{1, 2}, + expected: true, + }, + { + name: "many-same-unordered", + slice1: []int{1, 2}, + slice2: []int{2, 1}, + expected: true, + }, + { + name: "many-different-lengths", + slice1: []int{1}, + slice2: []int{2, 3}, + expected: false, + }, + { + name: "many-different", + slice1: []int{1, 2}, + slice2: []int{3, 4}, + expected: false, + }, + { + name: "many-different-duplicates-unordered", + slice1: []int{1, 2, 2, 3}, + slice2: []int{2, 1, 2, 4}, + expected: false, + }, + { + name: "many-same-duplicates-unordered", + slice1: []int{1, 2, 2}, + slice2: []int{2, 1, 2}, + expected: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := EqualIgnoreOrder(test.slice1, test.slice2) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestEqualIgnoreOrderString(t *testing.T) { + tests := []struct { + name string + slice1 []string + slice2 []string + expected bool + }{ + { + name: "nil-both", + slice1: nil, + slice2: nil, + expected: true, + }, + { + name: "nil-s1", + slice1: nil, + slice2: []string{"a"}, + expected: false, + }, + { + name: "nil-s2", + slice1: []string{"a"}, + slice2: nil, + expected: false, + }, + { + name: "empty-both", + slice1: []string{}, + slice2: []string{}, + expected: true, + }, + { + name: "empty-s1", + slice1: []string{}, + slice2: []string{"a"}, + expected: false, + }, + { + name: "empty-s2", + slice1: []string{"a"}, + slice2: []string{}, + expected: false, + }, + { + name: "nil-empty-mix-1", + slice1: nil, + slice2: []string{}, + expected: true, + }, + { + name: "nil-empty-mix-2", + slice1: []string{}, + slice2: nil, + expected: true, + }, + { + name: "one-same", + slice1: []string{"a"}, + slice2: []string{"a"}, + expected: true, + }, + { + name: "one-different", + slice1: []string{"a"}, + slice2: []string{"b"}, + expected: false, + }, + { + name: "many-same-ordered", + slice1: []string{"a", "b"}, + slice2: []string{"a", "b"}, + expected: true, + }, + { + name: "many-same-unordered", + slice1: []string{"a", "b"}, + slice2: []string{"b", "a"}, + expected: true, + }, + { + name: "many-different-lengths", + slice1: []string{"a"}, + slice2: []string{"b", "c"}, + expected: false, + }, + { + name: "many-different", + slice1: []string{"a", "b"}, + slice2: []string{"c", "d"}, + expected: false, + }, + { + name: "many-different-duplicates-unordered", + slice1: []string{"a", "b", "b", "c"}, + slice2: []string{"b", "a", "b", "d"}, + expected: false, + }, + { + name: "many-same-duplicates-unordered", + slice1: []string{"a", "b", "b"}, + slice2: []string{"b", "a", "b"}, + expected: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := EqualIgnoreOrder(test.slice1, test.slice2) + assert.Equal(t, test.expected, result) + }) + } +} From 42a25c196ce882f21558a17606058461e1ca5198 Mon Sep 17 00:00:00 2001 From: Olivier <osazos@adagio.io> Date: Tue, 9 Dec 2025 03:01:01 +0100 Subject: [PATCH 132/272] Adagio: Enable site capability (#4590) --- adapters/adagio/adagio.go | 3 +-- static/bidder-info/adagio.yaml | 7 ++++++- static/bidder-params/adagio.json | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/adapters/adagio/adagio.go b/adapters/adagio/adagio.go index 250b7d4424..eb551ead35 100644 --- a/adapters/adagio/adagio.go +++ b/adapters/adagio/adagio.go @@ -2,7 +2,6 @@ package adagio import ( "encoding/json" - "errors" "fmt" "net/http" @@ -64,7 +63,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest } if len(bidResponse.SeatBid) == 0 { - return nil, []error{errors.New("empty seatbid array")} + return nil, []error{&errortypes.BadServerResponse{Message: "empty seatbid array"}} } var errs []error diff --git a/static/bidder-info/adagio.yaml b/static/bidder-info/adagio.yaml index c5abf54d35..849665697b 100644 --- a/static/bidder-info/adagio.yaml +++ b/static/bidder-info/adagio.yaml @@ -22,4 +22,9 @@ capabilities: mediaTypes: - banner - video - - native \ No newline at end of file + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/adagio.json b/static/bidder-params/adagio.json index 709ca1a967..18c92172c2 100644 --- a/static/bidder-params/adagio.json +++ b/static/bidder-params/adagio.json @@ -10,7 +10,7 @@ }, "placement": { "type": "string", - "description": "Refers to the placement of an adunit in a page. Must not contain any information about the type of device." + "description": "Refers to the placement of an adunit in a page. See Adagio recommended values: https://prebid.org/dev-docs/bidders/adagio.html#recommended-placement-param-values." }, "site": { "type": "string", From 0c228b48ecf79ca0546743fa059b654df76a6600 Mon Sep 17 00:00:00 2001 From: Olivier <osazos@adagio.io> Date: Tue, 9 Dec 2025 03:45:41 +0100 Subject: [PATCH 133/272] Adagio: Remove hardcoded seat name (#4596) --- adapters/adagio/adagio.go | 1 - adapters/adagio/adagiotest/exemplary/banner-app.json | 1 - adapters/adagio/adagiotest/exemplary/banner-web.json | 1 - adapters/adagio/adagiotest/exemplary/multi-formats-app.json | 1 - adapters/adagio/adagiotest/exemplary/multi-formats-web.json | 1 - adapters/adagio/adagiotest/exemplary/multi-imps-app.json | 2 -- adapters/adagio/adagiotest/exemplary/multi-imps-web.json | 2 -- adapters/adagio/adagiotest/exemplary/native-app.json | 1 - adapters/adagio/adagiotest/exemplary/native-web.json | 1 - .../adagio/adagiotest/exemplary/request-with-rtd-module.json | 1 - adapters/adagio/adagiotest/exemplary/video-app.json | 1 - adapters/adagio/adagiotest/exemplary/video-web.json | 1 - 12 files changed, 14 deletions(-) diff --git a/adapters/adagio/adagio.go b/adapters/adagio/adagio.go index eb551ead35..cf5819e978 100644 --- a/adapters/adagio/adagio.go +++ b/adapters/adagio/adagio.go @@ -101,7 +101,6 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest Bid: &bid, BidMeta: meta, BidVideo: video, - Seat: openrtb_ext.BidderName(seatBid.Seat), BidType: bidType, } bidderResponse.Bids = append(bidderResponse.Bids, typedBid) diff --git a/adapters/adagio/adagiotest/exemplary/banner-app.json b/adapters/adagio/adagiotest/exemplary/banner-app.json index 38ea4a8828..2f73f25af7 100644 --- a/adapters/adagio/adagiotest/exemplary/banner-app.json +++ b/adapters/adagio/adagiotest/exemplary/banner-app.json @@ -181,7 +181,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/banner-web.json b/adapters/adagio/adagiotest/exemplary/banner-web.json index 51d344c526..417dc1b328 100644 --- a/adapters/adagio/adagiotest/exemplary/banner-web.json +++ b/adapters/adagio/adagiotest/exemplary/banner-web.json @@ -148,7 +148,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/multi-formats-app.json b/adapters/adagio/adagiotest/exemplary/multi-formats-app.json index ee0bfb428d..2d93603611 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-formats-app.json +++ b/adapters/adagio/adagiotest/exemplary/multi-formats-app.json @@ -207,7 +207,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/multi-formats-web.json b/adapters/adagio/adagiotest/exemplary/multi-formats-web.json index c62ca197a2..ec30ad5789 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-formats-web.json +++ b/adapters/adagio/adagiotest/exemplary/multi-formats-web.json @@ -174,7 +174,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/multi-imps-app.json b/adapters/adagio/adagiotest/exemplary/multi-imps-app.json index bbae86b26f..45523c2f86 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-imps-app.json +++ b/adapters/adagio/adagiotest/exemplary/multi-imps-app.json @@ -225,7 +225,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" }, { @@ -242,7 +241,6 @@ "h": 100, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/multi-imps-web.json b/adapters/adagio/adagiotest/exemplary/multi-imps-web.json index 619c14bd41..f5748e8c93 100644 --- a/adapters/adagio/adagiotest/exemplary/multi-imps-web.json +++ b/adapters/adagio/adagiotest/exemplary/multi-imps-web.json @@ -194,7 +194,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" }, { @@ -211,7 +210,6 @@ "h": 100, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/native-app.json b/adapters/adagio/adagiotest/exemplary/native-app.json index 2eb40c40c6..738fd0656b 100644 --- a/adapters/adagio/adagiotest/exemplary/native-app.json +++ b/adapters/adagio/adagiotest/exemplary/native-app.json @@ -152,7 +152,6 @@ ], "mtype": 4 }, - "seat": "adagio", "type": "native" } ] diff --git a/adapters/adagio/adagiotest/exemplary/native-web.json b/adapters/adagio/adagiotest/exemplary/native-web.json index 29a0a77eb2..7fd043fdd5 100644 --- a/adapters/adagio/adagiotest/exemplary/native-web.json +++ b/adapters/adagio/adagiotest/exemplary/native-web.json @@ -148,7 +148,6 @@ "h": 50, "mtype": 4 }, - "seat": "adagio", "type": "native" } ] diff --git a/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json b/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json index df8bd286f5..8662b8bcee 100644 --- a/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json +++ b/adapters/adagio/adagiotest/exemplary/request-with-rtd-module.json @@ -226,7 +226,6 @@ "h": 50, "mtype": 1 }, - "seat": "adagio", "type": "banner" } ] diff --git a/adapters/adagio/adagiotest/exemplary/video-app.json b/adapters/adagio/adagiotest/exemplary/video-app.json index 15a0af0b09..2d0bce73ec 100644 --- a/adapters/adagio/adagiotest/exemplary/video-app.json +++ b/adapters/adagio/adagiotest/exemplary/video-app.json @@ -165,7 +165,6 @@ "h": 720, "mtype": 2 }, - "seat": "adagio", "type": "video" } ] diff --git a/adapters/adagio/adagiotest/exemplary/video-web.json b/adapters/adagio/adagiotest/exemplary/video-web.json index 89189e359b..597df9d258 100644 --- a/adapters/adagio/adagiotest/exemplary/video-web.json +++ b/adapters/adagio/adagiotest/exemplary/video-web.json @@ -158,7 +158,6 @@ "h": 50, "mtype": 2 }, - "seat": "adagio", "type": "video" } ] From f829bea811ed7d43adc93e1b2f245b92f9f3ee25 Mon Sep 17 00:00:00 2001 From: linux019 <anode.dev@gmail.com> Date: Tue, 9 Dec 2025 04:57:26 +0200 Subject: [PATCH 134/272] Warn in auction response for bidders blocked by privacy settings (#4537) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- errortypes/code.go | 1 + exchange/utils.go | 4 ++++ exchange/utils_test.go | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/errortypes/code.go b/errortypes/code.go index 2e20f8ff9d..07b4727727 100644 --- a/errortypes/code.go +++ b/errortypes/code.go @@ -40,6 +40,7 @@ const ( InvalidUserUIDsWarningCode TooLongTargetingPrefixWarningCode TooShortTargetingPrefixWarningCode + BidderBlockedByPrivacySettings ) // Coder provides an error or warning code with severity. diff --git a/exchange/utils.go b/exchange/utils.go index 9659f19570..7606cd4248 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -190,6 +190,10 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, // privacy blocking if rs.isBidderBlockedByPrivacy(reqWrapperCopy, auctionReq.Activities, auctionPermissions, coreBidder, openrtb_ext.BidderName(bidder)) { + errs = append(errs, &errortypes.Warning{ + Message: fmt.Sprintf("bidder %q blocked by privacy settings", coreBidder), + WarningCode: errortypes.BidderBlockedByPrivacySettings, + }) continue } diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 317d7a640c..3585c71be3 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -2456,6 +2456,7 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) { gdprAllowedBidders []openrtb_ext.BidderName expectedBidders []openrtb_ext.BidderName expectedBlockedBidders []openrtb_ext.BidderName + expectedErrors []error }{ { description: "gdpr enforced, one request allowed and one request blocked", @@ -2463,6 +2464,10 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) { gdprAllowedBidders: []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, expectedBidders: []openrtb_ext.BidderName{openrtb_ext.BidderAppnexus}, expectedBlockedBidders: []openrtb_ext.BidderName{openrtb_ext.BidderRubicon}, + expectedErrors: []error{&errortypes.Warning{ + Message: `bidder "rubicon" blocked by privacy settings`, + WarningCode: errortypes.BidderBlockedByPrivacySettings, + }}, }, { description: "gdpr enforced, two requests allowed and no requests blocked", @@ -2531,7 +2536,7 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) { bidders = append(bidders, req.BidderName) } - assert.Empty(t, errs, test.description) + assert.Equal(t, test.expectedErrors, errs, test.description) assert.ElementsMatch(t, bidders, test.expectedBidders, test.description) for _, blockedBidder := range test.expectedBlockedBidders { @@ -5129,6 +5134,7 @@ func TestCleanOpenRTBRequestsActivities(t *testing.T) { expectedDevice openrtb2.Device expectedSource openrtb2.Source expectedImpExt json.RawMessage + expectedErrors []error }{ { name: "fetch_bids_request_with_one_bidder_allowed", @@ -5148,6 +5154,10 @@ func TestCleanOpenRTBRequestsActivities(t *testing.T) { expectedUser: expectedUserDefault, expectedDevice: expectedDeviceDefault, expectedSource: expectedSourceDefault, + expectedErrors: []error{&errortypes.Warning{ + Message: `bidder "appnexus" blocked by privacy settings`, + WarningCode: errortypes.BidderBlockedByPrivacySettings, + }}, }, { name: "transmit_ufpd_allowed", @@ -5292,7 +5302,7 @@ func TestCleanOpenRTBRequestsActivities(t *testing.T) { } bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, map[string]float64{}) - assert.Empty(t, errs) + assert.Equal(t, test.expectedErrors, errs) assert.Len(t, bidderRequests, test.expectedReqNumber) if test.expectedReqNumber == 1 { From f358e247272b6d2c3efade217e4cafa1b23762cb Mon Sep 17 00:00:00 2001 From: Eugene Dorfman <eugene.dorfman@gmail.com> Date: Tue, 9 Dec 2025 15:21:04 +0100 Subject: [PATCH 135/272] Logging: Add interface with default glog implementation (#4085) Co-authored-by: postindustria-code <oss@postindustria.com> --- README.md | 8 + analytics/agma/agma_module.go | 14 +- analytics/agma/sender.go | 12 +- analytics/build/build.go | 8 +- analytics/filesystem/file_module.go | 4 +- analytics/pubstack/config.go | 4 +- .../pubstack/eventchannel/eventchannel.go | 8 +- analytics/pubstack/eventchannel/sender.go | 10 +- analytics/pubstack/pubstack_module.go | 21 +- config/bidderinfo.go | 4 +- config/config.go | 15 +- config/stored_requests.go | 6 +- config/structlog.go | 8 +- config/util/loggers.go | 2 +- currency/rate_converter.go | 8 +- endpoints/cookie_sync.go | 4 +- endpoints/currency_rates.go | 4 +- endpoints/events/vtrack.go | 4 +- endpoints/info/bidders.go | 12 +- endpoints/info/bidders_detail.go | 6 +- endpoints/openrtb2/amp_auction.go | 12 +- endpoints/openrtb2/auction.go | 12 +- endpoints/openrtb2/video_auction.go | 6 +- endpoints/version.go | 4 +- exchange/bidder.go | 6 +- exchange/bidder_test.go | 10 +- exchange/exchange.go | 6 +- experiment/adscert/SignerLogger.go | 15 +- floors/fetcher.go | 22 +- floors/rule.go | 4 +- gdpr/vendorlist-fetching.go | 12 +- hooks/hookexecution/context.go | 4 +- hooks/hookexecution/execution.go | 4 +- hooks/plan.go | 4 +- logger/glog.go | 41 +++ logger/glog_test.go | 171 ++++++++++ logger/interface.go | 18 ++ logger/logger.go | 28 ++ logger/logger_test.go | 304 ++++++++++++++++++ main.go | 13 +- metrics/go_metrics.go | 34 +- .../devicedetection/device_info_extractor.go | 8 +- modules/modules.go | 4 +- modules/scope3/rtd/module.go | 4 +- modules/shutdown.go | 4 +- pbs/usersync.go | 8 +- prebid_cache_client/client.go | 4 +- router/router.go | 36 +-- server/listener.go | 6 +- server/prometheus.go | 10 +- server/server.go | 26 +- .../backends/db_fetcher/fetcher.go | 17 +- .../backends/db_provider/db_provider.go | 8 +- .../backends/http_fetcher/fetcher.go | 9 +- stored_requests/caches/memory/cache.go | 8 +- stored_requests/caches/memory/maps.go | 6 +- stored_requests/config/config.go | 25 +- stored_requests/events/database/database.go | 18 +- stored_requests/events/http/http.go | 20 +- 59 files changed, 839 insertions(+), 274 deletions(-) create mode 100644 logger/glog.go create mode 100644 logger/glog_test.go create mode 100644 logger/interface.go create mode 100644 logger/logger.go create mode 100644 logger/logger_test.go diff --git a/README.md b/README.md index 4c526b47a0..0aa629ebc2 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,14 @@ An option for developing Prebid Server in a reproducible environment isolated fr Prebid Server is not currently intended to be imported by other projects. Go Modules is used to manage dependencies, which also makes it possible to import Prebid Server packages. This is not supported. We offer no guarantees regarding the stability of packages and do not adhere to semantic versioning guidelines. +## Swapping Global Dependencies + +Logger is a global side-effectful dependency that sometimes needs to be swapped to modify the behavior. +The `Logger` package contains an interface definition for unstructured logging with built-in `glog` implementation. +The interface provides standard logging methods: `Debug`, `Info`, `Warn`, `Error`, and `Fatal`. +The `glog` implementation is based on `github.com/golang/glog` package and serves as the concrete implementation for the logging interface. +By default, the package uses the `glog` logger implementation. + ## Contributing > [!IMPORTANT] > All contributions must follow the [Prebid Code of Conduct](https://prebid.org/code-of-conduct/) and the [Prebid Module Rules](https://docs.prebid.org/dev-docs/module-rules.html). diff --git a/analytics/agma/agma_module.go b/analytics/agma/agma_module.go index 6ee16e93b8..1e544fe606 100644 --- a/analytics/agma/agma_module.go +++ b/analytics/agma/agma_module.go @@ -12,10 +12,10 @@ import ( "github.com/benbjohnson/clock" "github.com/docker/go-units" - "github.com/golang/glog" "github.com/prebid/go-gdpr/vendorconsent" "github.com/prebid/prebid-server/v3/analytics" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -93,7 +93,7 @@ func (l *AgmaLogger) start() { for { select { case <-l.sigTermCh: - glog.Infof("[AgmaAnalytics] Received Close, trying to flush buffer") + logger.Infof("[AgmaAnalytics] Received Close, trying to flush buffer") l.flush() return case event := <-l.bufferCh: @@ -139,7 +139,7 @@ func (l *AgmaLogger) flush() { if err != nil { l.reset() l.mux.Unlock() - glog.Warning("[AgmaAnalytics] fail to copy the buffer") + logger.Warnf("[AgmaAnalytics] fail to copy the buffer") return } @@ -223,7 +223,7 @@ func (l *AgmaLogger) LogAuctionObject(event *analytics.AuctionObject) { } data, err := serializeAnayltics(event.RequestWrapper, EventTypeAuction, code, event.StartTime) if err != nil { - glog.Errorf("[AgmaAnalytics] Error serializing auction object: %v", err) + logger.Errorf("[AgmaAnalytics] Error serializing auction object: %v", err) return } l.bufferCh <- data @@ -239,7 +239,7 @@ func (l *AgmaLogger) LogAmpObject(event *analytics.AmpObject) { } data, err := serializeAnayltics(event.RequestWrapper, EventTypeAmp, code, event.StartTime) if err != nil { - glog.Errorf("[AgmaAnalytics] Error serializing amp object: %v", err) + logger.Errorf("[AgmaAnalytics] Error serializing amp object: %v", err) return } l.bufferCh <- data @@ -255,14 +255,14 @@ func (l *AgmaLogger) LogVideoObject(event *analytics.VideoObject) { } data, err := serializeAnayltics(event.RequestWrapper, EventTypeVideo, code, event.StartTime) if err != nil { - glog.Errorf("[AgmaAnalytics] Error serializing video object: %v", err) + logger.Errorf("[AgmaAnalytics] Error serializing video object: %v", err) return } l.bufferCh <- data } func (l *AgmaLogger) Shutdown() { - glog.Info("[AgmaAnalytics] Shutdown, trying to flush buffer") + logger.Infof("[AgmaAnalytics] Shutdown, trying to flush buffer") l.flush() // mutex safe } diff --git a/analytics/agma/sender.go b/analytics/agma/sender.go index 7ae2849a82..e3f9c76852 100644 --- a/analytics/agma/sender.go +++ b/analytics/agma/sender.go @@ -10,8 +10,8 @@ import ( "net/url" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/version" ) @@ -51,7 +51,7 @@ func createHttpSender(httpClient *http.Client, endpoint config.AgmaAnalyticsHttp if endpoint.Gzip { requestBody, err = compressToGZIP(payload) if err != nil { - glog.Errorf("[agmaAnalytics] Compressing request failed %v", err) + logger.Errorf("[agmaAnalytics] Compressing request failed %v", err) return err } } else { @@ -60,7 +60,7 @@ func createHttpSender(httpClient *http.Client, endpoint config.AgmaAnalyticsHttp req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.Url, bytes.NewBuffer(requestBody)) if err != nil { - glog.Errorf("[agmaAnalytics] Creating request failed %v", err) + logger.Errorf("[agmaAnalytics] Creating request failed %v", err) return err } @@ -72,18 +72,18 @@ func createHttpSender(httpClient *http.Client, endpoint config.AgmaAnalyticsHttp resp, err := httpClient.Do(req) if err != nil { - glog.Errorf("[agmaAnalytics] Sending request failed %v", err) + logger.Errorf("[agmaAnalytics] Sending request failed %v", err) return err } defer func() { if _, err := io.Copy(io.Discard, resp.Body); err != nil { - glog.Errorf("[agmaAnalytics] Draining response body failed: %v", err) + logger.Errorf("[agmaAnalytics] Draining response body failed: %v", err) } resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - glog.Errorf("[agmaAnalytics] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) + logger.Errorf("[agmaAnalytics] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) return fmt.Errorf("wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) } return nil diff --git a/analytics/build/build.go b/analytics/build/build.go index 26edaa4f53..3fc3d212e2 100644 --- a/analytics/build/build.go +++ b/analytics/build/build.go @@ -4,13 +4,13 @@ import ( "encoding/json" "github.com/benbjohnson/clock" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/analytics" "github.com/prebid/prebid-server/v3/analytics/agma" "github.com/prebid/prebid-server/v3/analytics/clients" "github.com/prebid/prebid-server/v3/analytics/filesystem" "github.com/prebid/prebid-server/v3/analytics/pubstack" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/ortb" "github.com/prebid/prebid-server/v3/privacy" @@ -23,7 +23,7 @@ func New(analytics *config.Analytics) analytics.Runner { if mod, err := filesystem.NewFileLogger(analytics.File.Filename); err == nil { modules["filelogger"] = mod } else { - glog.Fatalf("Could not initialize FileLogger for file %v :%v", analytics.File.Filename, err) + logger.Fatalf("Could not initialize FileLogger for file %v :%v", analytics.File.Filename, err) } } @@ -40,7 +40,7 @@ func New(analytics *config.Analytics) analytics.Runner { if err == nil { modules["pubstack"] = pubstackModule } else { - glog.Errorf("Could not initialize PubstackModule: %v", err) + logger.Errorf("Could not initialize PubstackModule: %v", err) } } @@ -52,7 +52,7 @@ func New(analytics *config.Analytics) analytics.Runner { if err == nil { modules["agma"] = agmaModule } else { - glog.Errorf("Could not initialize Agma Anayltics: %v", err) + logger.Errorf("Could not initialize Agma Anayltics: %v", err) } } diff --git a/analytics/filesystem/file_module.go b/analytics/filesystem/file_module.go index 5555752e46..f2ab3c63d9 100644 --- a/analytics/filesystem/file_module.go +++ b/analytics/filesystem/file_module.go @@ -5,9 +5,9 @@ import ( "fmt" cglog "github.com/chasex/glog" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/analytics" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -94,7 +94,7 @@ func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent) // Shutdown the logger func (f *FileLogger) Shutdown() { // clear all pending buffered data in case there is any - glog.Info("[FileLogger] Shutdown, trying to flush buffer") + logger.Infof("[FileLogger] Shutdown, trying to flush buffer") f.Logger.Flush() } diff --git a/analytics/pubstack/config.go b/analytics/pubstack/config.go index 28330fc362..38ca4cb139 100644 --- a/analytics/pubstack/config.go +++ b/analytics/pubstack/config.go @@ -9,7 +9,7 @@ import ( "time" "github.com/docker/go-units" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) func fetchConfig(client *http.Client, endpoint *url.URL) (*Configuration, error) { @@ -21,7 +21,7 @@ func fetchConfig(client *http.Client, endpoint *url.URL) (*Configuration, error) // read the entire response body to ensure full connection reuse if there's an // error while decoding the json if _, err := io.Copy(io.Discard, res.Body); err != nil { - glog.Errorf("[pubstack] Draining config response body failed: %v", err) + logger.Errorf("[pubstack] Draining config response body failed: %v", err) } res.Body.Close() }() diff --git a/analytics/pubstack/eventchannel/eventchannel.go b/analytics/pubstack/eventchannel/eventchannel.go index 022cc5bcf1..bde37ee546 100644 --- a/analytics/pubstack/eventchannel/eventchannel.go +++ b/analytics/pubstack/eventchannel/eventchannel.go @@ -7,7 +7,7 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) type Metrics struct { @@ -66,7 +66,7 @@ func (c *EventChannel) buffer(event []byte) { _, err := c.gz.Write(event) if err != nil { - glog.Warning("[pubstack] fail to compress, skip the event") + logger.Warnf("[pubstack] fail to compress, skip the event") return } @@ -104,7 +104,7 @@ func (c *EventChannel) flush() { // finish writing gzip header err := c.gz.Close() if err != nil { - glog.Warning("[pubstack] fail to close gzipped buffer") + logger.Warnf("[pubstack] fail to close gzipped buffer") return } @@ -112,7 +112,7 @@ func (c *EventChannel) flush() { payload := make([]byte, c.buff.Len()) _, err = c.buff.Read(payload) if err != nil { - glog.Warning("[pubstack] fail to copy the buffer") + logger.Warnf("[pubstack] fail to copy the buffer") return } diff --git a/analytics/pubstack/eventchannel/sender.go b/analytics/pubstack/eventchannel/sender.go index c85c4fe446..61587ea941 100644 --- a/analytics/pubstack/eventchannel/sender.go +++ b/analytics/pubstack/eventchannel/sender.go @@ -8,7 +8,7 @@ import ( "net/url" "path" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) type Sender = func(payload []byte) error @@ -17,7 +17,7 @@ func NewHttpSender(client *http.Client, endpoint string) Sender { return func(payload []byte) error { req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(payload)) if err != nil { - glog.Error(err) + logger.Errorf("%v", err) return err } @@ -30,13 +30,13 @@ func NewHttpSender(client *http.Client, endpoint string) Sender { } defer func() { if _, err := io.Copy(io.Discard, resp.Body); err != nil { - glog.Errorf("[pubstack] Draining sender response body failed: %v", err) + logger.Errorf("[pubstack] Draining sender response body failed: %v", err) } resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - glog.Errorf("[pubstack] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) + logger.Errorf("[pubstack] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) return fmt.Errorf("wrong code received %d instead of %d", resp.StatusCode, http.StatusOK) } return nil @@ -46,7 +46,7 @@ func NewHttpSender(client *http.Client, endpoint string) Sender { func BuildEndpointSender(client *http.Client, baseUrl string, module string) Sender { endpoint, err := url.Parse(baseUrl) if err != nil { - glog.Error(err) + logger.Errorf("%v", err) } endpoint.Path = path.Join(endpoint.Path, "intake", module) return NewHttpSender(client, endpoint.String()) diff --git a/analytics/pubstack/pubstack_module.go b/analytics/pubstack/pubstack_module.go index c5bb02e2eb..9a8116951d 100644 --- a/analytics/pubstack/pubstack_module.go +++ b/analytics/pubstack/pubstack_module.go @@ -10,11 +10,10 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/golang/glog" - "github.com/prebid/prebid-server/v3/analytics" "github.com/prebid/prebid-server/v3/analytics/pubstack/eventchannel" "github.com/prebid/prebid-server/v3/analytics/pubstack/helpers" + "github.com/prebid/prebid-server/v3/logger" ) type Configuration struct { @@ -64,7 +63,7 @@ func NewModule(client *http.Client, scope, endpoint, configRefreshDelay string, } func NewModuleWithConfigTask(client *http.Client, scope, endpoint string, maxEventCount int, maxByteSize, maxTime string, configTask ConfigUpdateTask, clock clock.Clock) (analytics.Module, error) { - glog.Infof("[pubstack] Initializing module scope=%s endpoint=%s\n", scope, endpoint) + logger.Infof("[pubstack] Initializing module scope=%s endpoint=%s\n", scope, endpoint) // parse args bufferCfg, err := newBufferConfig(maxEventCount, maxByteSize, maxTime) @@ -103,7 +102,7 @@ func NewModuleWithConfigTask(client *http.Client, scope, endpoint string, maxEve configChannel := configTask.Start(pb.stopCh) go pb.start(configChannel) - glog.Info("[pubstack] Pubstack analytics configured and ready") + logger.Infof("[pubstack] Pubstack analytics configured and ready") return &pb, nil } @@ -118,7 +117,7 @@ func (p *PubstackModule) LogAuctionObject(ao *analytics.AuctionObject) { // serialize event payload, err := helpers.JsonifyAuctionObject(ao, p.scope) if err != nil { - glog.Warning("[pubstack] Cannot serialize auction") + logger.Warnf("[pubstack] Cannot serialize auction") return } @@ -139,7 +138,7 @@ func (p *PubstackModule) LogVideoObject(vo *analytics.VideoObject) { // serialize event payload, err := helpers.JsonifyVideoObject(vo, p.scope) if err != nil { - glog.Warning("[pubstack] Cannot serialize video") + logger.Warnf("[pubstack] Cannot serialize video") return } @@ -157,7 +156,7 @@ func (p *PubstackModule) LogSetUIDObject(so *analytics.SetUIDObject) { // serialize event payload, err := helpers.JsonifySetUIDObject(so, p.scope) if err != nil { - glog.Warning("[pubstack] Cannot serialize video") + logger.Warnf("[pubstack] Cannot serialize video") return } @@ -175,7 +174,7 @@ func (p *PubstackModule) LogCookieSyncObject(cso *analytics.CookieSyncObject) { // serialize event payload, err := helpers.JsonifyCookieSync(cso, p.scope) if err != nil { - glog.Warning("[pubstack] Cannot serialize video") + logger.Warnf("[pubstack] Cannot serialize video") return } @@ -193,7 +192,7 @@ func (p *PubstackModule) LogAmpObject(ao *analytics.AmpObject) { // serialize event payload, err := helpers.JsonifyAmpObject(ao, p.scope) if err != nil { - glog.Warning("[pubstack] Cannot serialize video") + logger.Warnf("[pubstack] Cannot serialize video") return } @@ -203,7 +202,7 @@ func (p *PubstackModule) LogAmpObject(ao *analytics.AmpObject) { // Shutdown - no op since the analytic module already implements system signal handling // and trying to close a closed channel will cause panic func (p *PubstackModule) Shutdown() { - glog.Info("[PubstackModule] Shutdown") + logger.Infof("[PubstackModule] Shutdown") } func (p *PubstackModule) start(c <-chan *Configuration) { @@ -216,7 +215,7 @@ func (p *PubstackModule) start(c <-chan *Configuration) { return case config := <-c: p.updateConfig(config) - glog.Infof("[pubstack] Updating config: %v", p.cfg) + logger.Infof("[pubstack] Updating config: %v", p.cfg) } } } diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 1f4041ec95..d3873bf2e9 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -3,12 +3,12 @@ package config import ( "errors" "fmt" - "log" "os" "path/filepath" "strings" "text/template" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/ptrutil" @@ -285,7 +285,7 @@ const ( func (r InfoReaderFromDisk) Read() (map[string][]byte, error) { bidderConfigs, err := os.ReadDir(r.Path) if err != nil { - log.Fatal(err) + logger.Fatalf("%v", err) } bidderInfos := make(map[string][]byte) diff --git a/config/config.go b/config/config.go index 65f871ed97..eae0d981d3 100644 --- a/config/config.go +++ b/config/config.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "github.com/golang/glog" "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" "github.com/spf13/viper" @@ -176,11 +176,11 @@ func (cfg *Configuration) validate(v *viper.Viper) []error { errs = cfg.ExtCacheURL.validate(errs) errs = cfg.AccountDefaults.PriceFloors.validate(errs) if cfg.AccountDefaults.Disabled { - glog.Warning(`With account_defaults.disabled=true, host-defined accounts must exist and have "disabled":false. All other requests will be rejected.`) + logger.Warnf(`With account_defaults.disabled=true, host-defined accounts must exist and have "disabled":false. All other requests will be rejected.`) } if cfg.AccountDefaults.Events.Enabled { - glog.Warning(`account_defaults.events has no effect as the feature is under development.`) + logger.Warnf(`account_defaults.events has no effect as the feature is under development.`) } errs = cfg.Experiment.validate(errs) @@ -292,7 +292,7 @@ func (cfg *GDPR) validate(v *viper.Viper, errs []error) []error { errs = append(errs, fmt.Errorf("gdpr.host_vendor_id must be in the range [0, %d]. Got %d", 0xffff, cfg.HostVendorID)) } if cfg.HostVendorID == 0 { - glog.Warning("gdpr.host_vendor_id was not specified. Host company GDPR checks will be skipped.") + logger.Warnf("gdpr.host_vendor_id was not specified. Host company GDPR checks will be skipped.") } if cfg.AMPException { errs = append(errs, fmt.Errorf("gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)")) @@ -757,7 +757,8 @@ func New(v *viper.Viper, bidderInfos BidderInfos, normalizeBidderName openrtb_ex } if err := isValidCookieSize(c.HostCookie.MaxCookieSizeBytes); err != nil { - glog.Fatal(fmt.Printf("Max cookie size %d cannot be less than %d \n", c.HostCookie.MaxCookieSizeBytes, MIN_COOKIE_SIZE_BYTES)) + logger.Fatalf("Max cookie size %d cannot be less than %d \n", c.HostCookie.MaxCookieSizeBytes, MIN_COOKIE_SIZE_BYTES) + return nil, err } @@ -847,7 +848,7 @@ func New(v *viper.Viper, bidderInfos BidderInfos, normalizeBidderName openrtb_ex } c.BidderInfos = mergedBidderInfos - glog.Info("Logging the resolved configuration:") + logger.Infof("Logging the resolved configuration:") logGeneral(reflect.ValueOf(c), " \t") if errs := c.validate(v); len(errs) > 0 { return &c, errortypes.NewAggregateError("validation errors", errs) @@ -890,7 +891,7 @@ func setConfigBidderInfoNillableFields(v *viper.Viper, bidderInfos BidderInfos) func (cfg *Configuration) MarshalAccountDefaults() error { var err error if cfg.accountDefaultsJSON, err = jsonutil.Marshal(cfg.AccountDefaults); err != nil { - glog.Warningf("converting %+v to json: %v", cfg.AccountDefaults, err) + logger.Warnf("converting %+v to json: %v", cfg.AccountDefaults, err) } return err } diff --git a/config/stored_requests.go b/config/stored_requests.go index 2e8d1e7f88..73acc1bf06 100644 --- a/config/stored_requests.go +++ b/config/stored_requests.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) // DataType constants @@ -358,7 +358,7 @@ func (cfg *InMemoryCache) validate(dataType DataType, errs []error) []error { errs = append(errs, fmt.Errorf("%s: in_memory_cache.size_bytes must be >= 0 when in_memory_cache.type=lru. Got %d", section, cfg.Size)) } if cfg.RequestCacheSize > 0 || cfg.ImpCacheSize > 0 || cfg.RespCacheSize > 0 { - glog.Warningf("%s: in_memory_cache.request_cache_size_bytes, imp_cache_size_bytes and resp_cache_size_bytes do not apply to this section and will be ignored", section) + logger.Warnf("%s: in_memory_cache.request_cache_size_bytes, imp_cache_size_bytes and resp_cache_size_bytes do not apply to this section and will be ignored", section) } } else { // dual (request and imp) caches @@ -372,7 +372,7 @@ func (cfg *InMemoryCache) validate(dataType DataType, errs []error) []error { errs = append(errs, fmt.Errorf("%s: in_memory_cache.resp_cache_size_bytes must be >= 0 when in_memory_cache.type=lru. Got %d", section, cfg.RespCacheSize)) } if cfg.Size > 0 { - glog.Warningf("%s: in_memory_cache.size_bytes does not apply in this section and will be ignored", section) + logger.Warnf("%s: in_memory_cache.size_bytes does not apply in this section and will be ignored", section) } } default: diff --git a/config/structlog.go b/config/structlog.go index 911f475717..6faec25cc5 100644 --- a/config/structlog.go +++ b/config/structlog.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - "github.com/golang/glog" + logInternal "github.com/prebid/prebid-server/v3/logger" ) type logMsg func(string, ...interface{}) @@ -20,7 +20,7 @@ var blocklistregexp = []*regexp.Regexp{ // prefix if you want that name to be logged. Structs will append .<fieldname> recursively to the prefix // to document deeper structure. func logGeneral(v reflect.Value, prefix string) { - logGeneralWithLogger(v, prefix, glog.Infof) + logGeneralWithLogger(v, prefix, logInternal.Infof) } func logGeneralWithLogger(v reflect.Value, prefix string, logger logMsg) { @@ -45,7 +45,7 @@ func logGeneralWithLogger(v reflect.Value, prefix string, logger logMsg) { func logStructWithLogger(v reflect.Value, prefix string, logger logMsg) { if v.Kind() != reflect.Struct { - glog.Fatalf("LogStruct called on type %s, whuch is not a struct!", v.Type().String()) + logInternal.Fatalf("LogStruct called on type %s, whuch is not a struct!", v.Type().String()) } t := v.Type() for i := 0; i < t.NumField(); i++ { @@ -60,7 +60,7 @@ func logStructWithLogger(v reflect.Value, prefix string, logger logMsg) { func logMapWithLogger(v reflect.Value, prefix string, logger logMsg) { if v.Kind() != reflect.Map { - glog.Fatalf("LogMap called on type %s, whuch is not a map!", v.Type().String()) + logInternal.Fatalf("LogMap called on type %s, whuch is not a map!", v.Type().String()) } for _, k := range v.MapKeys() { if k.Kind() == reflect.String && !allowedName(k.String()) { diff --git a/config/util/loggers.go b/config/util/loggers.go index d9aad43a7f..0731376e15 100644 --- a/config/util/loggers.go +++ b/config/util/loggers.go @@ -4,7 +4,7 @@ import ( "math/rand" ) -type LogMsg func(string, ...interface{}) +type LogMsg func(string, ...any) type randomGenerator func() float32 diff --git a/currency/rate_converter.go b/currency/rate_converter.go index d1898a59a2..c791c9b665 100644 --- a/currency/rate_converter.go +++ b/currency/rate_converter.go @@ -8,8 +8,8 @@ import ( "sync/atomic" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/util/jsonutil" "github.com/prebid/prebid-server/v3/util/timeutil" ) @@ -63,7 +63,7 @@ func (rc *RateConverter) fetch() (*Rates, error) { // read the entire response body to ensure full connection reuse if there's an // invalid status code if _, err := io.Copy(io.Discard, response.Body); err != nil { - glog.Errorf("error draining conversion rates response body: %v", err) + logger.Errorf("error draining conversion rates response body: %v", err) } response.Body.Close() }() @@ -96,9 +96,9 @@ func (rc *RateConverter) update() error { } else { if rc.checkStaleRates() { rc.clearRates() - glog.Errorf("Error updating conversion rates, falling back to constant rates: %v", err) + logger.Errorf("Error updating conversion rates, falling back to constant rates: %v", err) } else { - glog.Errorf("Error updating conversion rates: %v", err) + logger.Errorf("Error updating conversion rates: %v", err) } } diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index 6a836ed976..a90bc6117d 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" @@ -21,6 +20,7 @@ import ( "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/gdpr" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" @@ -458,7 +458,7 @@ func (c *cookieSyncEndpoint) handleResponse(w http.ResponseWriter, tf usersync.S syncTypes := tf.ForBidder(syncerChoice.Bidder) sync, err := syncerChoice.Syncer.GetSync(syncTypes, m) if err != nil { - glog.Errorf("Failed to get usersync info for %s: %v", syncerChoice.Bidder, err) + logger.Errorf("Failed to get usersync info for %s: %v", syncerChoice.Bidder, err) continue } diff --git a/endpoints/currency_rates.go b/endpoints/currency_rates.go index 9d27fb2497..f7d20cd79b 100644 --- a/endpoints/currency_rates.go +++ b/endpoints/currency_rates.go @@ -4,8 +4,8 @@ import ( "net/http" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/currency" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -62,7 +62,7 @@ func NewCurrencyRatesEndpoint(rateConverter rateConverter, fetchingInterval time return func(w http.ResponseWriter, _ *http.Request) { jsonOutput, err := jsonutil.Marshal(currencyRateInfo) if err != nil { - glog.Errorf("/currency/rates Critical error when trying to marshal currencyRateInfo: %v", err) + logger.Errorf("/currency/rates Critical error when trying to marshal currencyRateInfo: %v", err) w.WriteHeader(http.StatusInternalServerError) return } diff --git a/endpoints/events/vtrack.go b/endpoints/events/vtrack.go index 590243bb5c..ff846f694f 100644 --- a/endpoints/events/vtrack.go +++ b/endpoints/events/vtrack.go @@ -9,12 +9,12 @@ import ( "strings" "time" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" accountService "github.com/prebid/prebid-server/v3/account" "github.com/prebid/prebid-server/v3/analytics" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/prebid_cache_client" @@ -213,7 +213,7 @@ func (v *vtrackEndpoint) handleVTrackRequest(ctx context.Context, req *BidCacheR // handle pbs caching errors if len(errs) != 0 { - glog.Errorf("Error(s) updating vast: %v", errs) + logger.Errorf("Error(s) updating vast: %v", errs) return nil, errs } diff --git a/endpoints/info/bidders.go b/endpoints/info/bidders.go index 5de9c05a23..d5f6ea330f 100644 --- a/endpoints/info/bidders.go +++ b/endpoints/info/bidders.go @@ -5,9 +5,9 @@ import ( "sort" "strings" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -18,22 +18,22 @@ var invalidBaseAdaptersOnlyMsg = []byte(`Invalid value for 'baseadaptersonly' qu func NewBiddersEndpoint(bidders config.BidderInfos) httprouter.Handle { responseAll, err := prepareBiddersResponseAll(bidders) if err != nil { - glog.Fatalf("error creating /info/bidders endpoint all bidders response: %v", err) + logger.Fatalf("error creating /info/bidders endpoint all bidders response: %v", err) } responseAllBaseOnly, err := prepareBiddersResponseAllBaseOnly(bidders) if err != nil { - glog.Fatalf("error creating /info/bidders endpoint all bidders (base adapters only) response: %v", err) + logger.Fatalf("error creating /info/bidders endpoint all bidders (base adapters only) response: %v", err) } responseEnabledOnly, err := prepareBiddersResponseEnabledOnly(bidders) if err != nil { - glog.Fatalf("error creating /info/bidders endpoint enabled only response: %v", err) + logger.Fatalf("error creating /info/bidders endpoint enabled only response: %v", err) } responseEnabledOnlyBaseOnly, err := prepareBiddersResponseEnabledOnlyBaseOnly(bidders) if err != nil { - glog.Fatalf("error creating /info/bidders endpoint enabled only (base adapters only) response: %v", err) + logger.Fatalf("error creating /info/bidders endpoint enabled only (base adapters only) response: %v", err) } return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -137,6 +137,6 @@ func writeResponse(w http.ResponseWriter, data []byte) { func writeWithErrorHandling(w http.ResponseWriter, data []byte) { if _, err := w.Write(data); err != nil { - glog.Errorf("error writing response to /info/bidders: %v", err) + logger.Errorf("error writing response to /info/bidders: %v", err) } } diff --git a/endpoints/info/bidders_detail.go b/endpoints/info/bidders_detail.go index 098dad032e..1a0936a07b 100644 --- a/endpoints/info/bidders_detail.go +++ b/endpoints/info/bidders_detail.go @@ -6,9 +6,9 @@ import ( "net/http" "strings" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -22,7 +22,7 @@ const ( func NewBiddersDetailEndpoint(bidders config.BidderInfos) httprouter.Handle { responses, err := prepareBiddersDetailResponse(bidders) if err != nil { - glog.Fatalf("error creating /info/bidders/<bidder> endpoint response: %v", err) + logger.Fatalf("error creating /info/bidders/<bidder> endpoint response: %v", err) } return func(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { @@ -36,7 +36,7 @@ func NewBiddersDetailEndpoint(bidders config.BidderInfos) httprouter.Handle { if response, ok := responses[bidderName]; ok { w.Header().Set("Content-Type", "application/json") if _, err := w.Write(response); err != nil { - glog.Errorf("error writing response to /info/bidders/%s: %v", bidder, err) + logger.Errorf("error writing response to /info/bidders/%s: %v", bidder, err) } } else { w.WriteHeader(http.StatusNotFound) diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 37419e4a59..48a80d9cab 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -12,7 +12,6 @@ import ( "time" "github.com/buger/jsonparser" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" @@ -28,6 +27,7 @@ import ( "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/exchange" "github.com/prebid/prebid-server/v3/hooks" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/privacy" @@ -293,7 +293,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h if err != nil && !isRejectErr { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Critical error while running the auction: %v", err) - glog.Errorf("/openrtb2/amp Critical error: %v", err) + logger.Errorf("/openrtb2/amp Critical error: %v", err) ao.Status = http.StatusInternalServerError ao.Errors = append(ao.Errors, err) return @@ -304,7 +304,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h if err := reqWrapper.RebuildRequest(); err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Critical error while running the auction: %v", err) - glog.Errorf("/openrtb2/amp Critical error: %v", err) + logger.Errorf("/openrtb2/amp Critical error: %v", err) ao.Status = http.StatusInternalServerError ao.Errors = append(ao.Errors, err) return @@ -368,7 +368,7 @@ func sendAmpResponse( if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Critical error while unpacking AMP targets: %v", err) - glog.Errorf("/openrtb2/amp Critical error unpacking targets: %v", err) + logger.Errorf("/openrtb2/amp Critical error unpacking targets: %v", err) ao.Errors = append(ao.Errors, fmt.Errorf("Critical error while unpacking AMP targets: %v", err)) ao.Status = http.StatusInternalServerError return labels, ao @@ -471,7 +471,7 @@ func getExtBidResponse( if extResponse.Debug != nil { extBidResponse.Debug = extResponse.Debug } else { - glog.Errorf("Test set on request but debug not present in response.") + logger.Errorf("Test set on request but debug not present in response.") ao.Errors = append(ao.Errors, fmt.Errorf("test set on request but debug not present in response")) } } @@ -481,7 +481,7 @@ func getExtBidResponse( modules, warns, err := hookexecution.GetModulesJSON(stageOutcomes, reqWrapper.BidRequest, account) if err != nil { err := fmt.Errorf("Failed to get modules outcome: %s", err) - glog.Errorf(err.Error()) + logger.Errorf("%v", err.Error()) ao.Errors = append(ao.Errors, err) } else if modules != nil { extBidResponse.Prebid = &openrtb_ext.ExtResponsePrebid{Modules: modules} diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index f03e6bc489..0eaf0e302e 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -16,7 +16,6 @@ import ( "github.com/buger/jsonparser" "github.com/gofrs/uuid" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" gpplib "github.com/prebid/go-gpp" "github.com/prebid/go-gpp/constants" @@ -24,6 +23,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb3" "github.com/prebid/prebid-server/v3/bidadjustment" "github.com/prebid/prebid-server/v3/hooks" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/ortb" "github.com/prebid/prebid-server/v3/privacy" "github.com/prebid/prebid-server/v3/privacysandbox" @@ -287,7 +287,7 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http labels.RequestStatus = metrics.RequestStatusErr w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Critical error while running the auction: %v", err) - glog.Errorf("/openrtb2/auction Critical error: %v", err) + logger.Errorf("/openrtb2/auction Critical error: %v", err) ao.Status = http.StatusInternalServerError ao.Errors = append(ao.Errors, err) return @@ -298,7 +298,7 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http err = setSeatNonBidRaw(req, auctionResponse) if err != nil { - glog.Errorf("Error setting seat non-bid: %v", err) + logger.Errorf("Error setting seat non-bid: %v", err) } labels, ao = sendAuctionResponse(w, hookExecutor, response, req.BidRequest, account, labels, ao) } @@ -368,7 +368,7 @@ func sendAuctionResponse( ext, warns, err := hookexecution.EnrichExtBidResponse(response.Ext, stageOutcomes, request, account) if err != nil { err = fmt.Errorf("Failed to enrich Bid Response with hook debug information: %s", err) - glog.Errorf(err.Error()) + logger.Errorf("%v", err) ao.Errors = append(ao.Errors, err) } else { response.Ext = ext @@ -466,7 +466,7 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metric if rejectErr != nil { errs = []error{rejectErr} if err = jsonutil.UnmarshalValid(requestJson, req.BidRequest); err != nil { - glog.Errorf("Failed to unmarshal BidRequest during entrypoint rejection: %s", err) + logger.Errorf("Failed to unmarshal BidRequest during entrypoint rejection: %s", err) } return } @@ -514,7 +514,7 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metric if rejectErr != nil { errs = []error{rejectErr} if err = jsonutil.UnmarshalValid(requestJson, req.BidRequest); err != nil { - glog.Errorf("Failed to unmarshal BidRequest during raw auction stage rejection: %s", err) + logger.Errorf("Failed to unmarshal BidRequest during raw auction stage rejection: %s", err) } return } diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index e82981c3d4..047511f379 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -14,11 +14,11 @@ import ( "github.com/buger/jsonparser" "github.com/gofrs/uuid" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/hooks" "github.com/prebid/prebid-server/v3/hooks/hookexecution" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/ortb" "github.com/prebid/prebid-server/v3/privacy" jsonpatch "gopkg.in/evanphx/json-patch.v5" @@ -371,7 +371,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re if bidReq.Test == 1 { err = setSeatNonBidRaw(bidReqWrapper, auctionResponse) if err != nil { - glog.Errorf("Error setting seat non-bid: %v", err) + logger.Errorf("Error setting seat non-bid: %v", err) } bidResp.Ext = response.Ext } @@ -441,7 +441,7 @@ func handleError(labels *metrics.Labels, w http.ResponseWriter, errL []error, vo w.WriteHeader(status) vo.Status = status fmt.Fprintf(w, "Critical error while running the video endpoint: %v", errors) - glog.Errorf("/openrtb2/video Critical error: %v", errors) + logger.Errorf("/openrtb2/video Critical error: %v", errors) vo.Errors = append(vo.Errors, errL...) } diff --git a/endpoints/version.go b/endpoints/version.go index 8eb305c3f5..b947c771fb 100644 --- a/endpoints/version.go +++ b/endpoints/version.go @@ -4,7 +4,7 @@ import ( "encoding/json" "net/http" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -14,7 +14,7 @@ const versionEndpointValueNotSet = "not-set" func NewVersionEndpoint(version, revision string) http.HandlerFunc { response, err := prepareVersionEndpointResponse(version, revision) if err != nil { - glog.Fatalf("error creating /version endpoint response: %v", err) + logger.Fatalf("error creating /version endpoint response: %v", err) } return func(w http.ResponseWriter, _ *http.Request) { diff --git a/exchange/bidder.go b/exchange/bidder.go index 8e2c235dc9..264a03d46e 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -19,13 +19,13 @@ import ( "sync/atomic" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/bidadjustment" "github.com/prebid/prebid-server/v3/config/util" "github.com/prebid/prebid-server/v3/currency" "github.com/prebid/prebid-server/v3/exchange/entities" "github.com/prebid/prebid-server/v3/experiment/adscert" "github.com/prebid/prebid-server/v3/hooks/hookexecution" + loggerI "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/version" "github.com/prebid/openrtb/v20/adcom1" @@ -570,7 +570,7 @@ func makeExt(httpInfo *httpCallInfo) *openrtb_ext.ExtHttpCall { // Bidder interface. func (bidder *BidderAdapter) doRequest(ctx context.Context, req *adapters.RequestData, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo { if bidder.shouldRequest() { - return bidder.doRequestImpl(ctx, req, glog.Warningf, bidderRequestStartTime, tmaxAdjustments) + return bidder.doRequestImpl(ctx, req, loggerI.Warnf, bidderRequestStartTime, tmaxAdjustments) } return &httpCallInfo{ request: req, @@ -683,7 +683,7 @@ func (bidder *BidderAdapter) doTimeoutNotification(timeoutBidder adapters.Timeou if err == nil { defer func() { if _, err := io.Copy(io.Discard, httpResp.Body); err != nil { - glog.Errorf("TimeoutNotification: Draining response body failed %v", err) + loggerI.Errorf("TimeoutNotification: Draining response body failed %v", err) } httpResp.Body.Close() }() diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index 2d9caf097c..eb061ee691 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -21,7 +21,6 @@ import ( "testing" "time" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/adcom1" nativeRequests "github.com/prebid/openrtb/v20/native1/request" nativeResponse "github.com/prebid/openrtb/v20/native1/response" @@ -33,6 +32,7 @@ import ( "github.com/prebid/prebid-server/v3/exchange/entities" "github.com/prebid/prebid-server/v3/experiment/adscert" "github.com/prebid/prebid-server/v3/hooks/hookexecution" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" "github.com/prebid/prebid-server/v3/openrtb_ext" @@ -2213,7 +2213,7 @@ func TestTimeoutNotificationOff(t *testing.T) { if tb, ok := bidder.Bidder.(adapters.TimeoutBidder); !ok { t.Error("Failed to cast bidder to a TimeoutBidder") } else { - bidder.doTimeoutNotification(tb, &adapters.RequestData{}, glog.Warningf) + bidder.doTimeoutNotification(tb, &adapters.RequestData{}, logger.Warnf) } } @@ -2268,7 +2268,7 @@ func TestTimeoutNotificationOn(t *testing.T) { } var loggerBuffer bytes.Buffer - logger := func(msg string, args ...interface{}) { + logger := func(msg string, args ...any) { loggerBuffer.WriteString(fmt.Sprintf(fmt.Sprintln(msg), args...)) } tmaxAdjustments := &TmaxAdjustmentsPreprocessed{} @@ -3389,7 +3389,7 @@ func TestDoRequestImplWithTmax(t *testing.T) { me: &metricsConfig.NilMetricsEngine{}, Client: server.Client(), } - logger := func(msg string, args ...interface{}) {} + logger := func(msg string, args ...any) {} tests := []struct { ctxDeadline time.Time @@ -3464,7 +3464,7 @@ func TestDoRequestImplWithTmaxTimeout(t *testing.T) { me: metricsMock, Client: server.Client(), } - logger := func(msg string, args ...interface{}) {} + logger := func(msg string, args ...any) {} tests := []struct { ctxDeadline time.Time diff --git a/exchange/exchange.go b/exchange/exchange.go index 1915e7b273..ef24e3fc9c 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -27,6 +27,7 @@ import ( "github.com/prebid/prebid-server/v3/floors" "github.com/prebid/prebid-server/v3/gdpr" "github.com/prebid/prebid-server/v3/hooks/hookexecution" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" @@ -41,7 +42,6 @@ import ( "github.com/buger/jsonparser" "github.com/gofrs/uuid" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" ) @@ -743,7 +743,7 @@ func (e *exchange) getAllBids( bidderRunner := e.recoverSafely(bidderRequests, func(bidderRequest BidderRequest, conversions currency.Conversions) { // Passing in aName so a doesn't change out from under the go routine if bidderRequest.BidderLabels.Adapter == "" { - glog.Errorf("Exchange: bidlables for %s (%s) missing adapter string", bidderRequest.BidderName, bidderRequest.BidderCoreName) + logger.Errorf("Exchange: bidlables for %s (%s) missing adapter string", bidderRequest.BidderName, bidderRequest.BidderCoreName) bidderRequest.BidderLabels.Adapter = bidderRequest.BidderCoreName } brw := new(bidResponseWrapper) @@ -878,7 +878,7 @@ func (e *exchange) recoverSafely(bidderRequests []BidderRequest, allBidders = sb.String()[:sb.Len()-1] } - glog.Errorf("OpenRTB auction recovered panic from Bidder %s: %v. "+ + logger.Errorf("OpenRTB auction recovered panic from Bidder %s: %v. "+ "Account id: %s, All Bidders: %s, Stack trace is: %v", bidderRequest.BidderCoreName, r, bidderRequest.BidderLabels.PubID, allBidders, string(debug.Stack())) e.me.RecordAdapterPanic(bidderRequest.BidderLabels) diff --git a/experiment/adscert/SignerLogger.go b/experiment/adscert/SignerLogger.go index 1d99bcc63f..798e9bd2a1 100644 --- a/experiment/adscert/SignerLogger.go +++ b/experiment/adscert/SignerLogger.go @@ -2,7 +2,8 @@ package adscert import ( "fmt" - "github.com/golang/glog" + + "github.com/prebid/prebid-server/v3/logger" ) type SignerLogger struct { @@ -10,27 +11,27 @@ type SignerLogger struct { func (sl *SignerLogger) Debugf(format string, args ...interface{}) { //there is no Debug level in glog - glog.Infof(format, args...) + logger.Infof(format, args...) } func (sl *SignerLogger) Infof(format string, args ...interface{}) { - glog.Infof(format, args...) + logger.Infof(format, args...) } func (sl *SignerLogger) Info(format string) { - glog.Info(format) + logger.Infof(format) } func (sl *SignerLogger) Warningf(format string, args ...interface{}) { - glog.Warningf(format, args...) + logger.Warnf(format, args...) } func (sl *SignerLogger) Errorf(format string, args ...interface{}) { - glog.Errorf(format, args...) + logger.Errorf(format, args...) } func (sl *SignerLogger) Fatalf(format string, args ...interface{}) { - glog.Fatalf(format, args...) + logger.Fatalf(format, args...) } func (sl *SignerLogger) Panicf(format string, args ...interface{}) { diff --git a/floors/fetcher.go b/floors/fetcher.go index c48b45fd7a..c3d2a02f78 100644 --- a/floors/fetcher.go +++ b/floors/fetcher.go @@ -14,8 +14,8 @@ import ( "github.com/alitto/pond" validator "github.com/asaskevich/govalidator" "github.com/coocood/freecache" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/timeutil" @@ -90,7 +90,7 @@ func (fq *FetchQueue) Top() *fetchInfo { } func workerPanicHandler(p interface{}) { - glog.Errorf("floor fetcher worker panicked: %v", p) + logger.Errorf("floor fetcher worker panicked: %v", p) } func NewPriceFloorFetcher(config config.PriceFloors, httpClient *http.Client, metricEngine metrics.MetricsEngine) *PriceFloorFetcher { @@ -165,7 +165,7 @@ func (f *PriceFloorFetcher) worker(fetchConfig fetchInfo) { } floorData, err := json.Marshal(floorData) if err != nil { - glog.Errorf("Error while marshaling fetched floor data for url %s", fetchConfig.AccountFloorFetch.URL) + logger.Errorf("Error while marshaling fetched floor data for url %s", fetchConfig.AccountFloorFetch.URL) } else { f.SetWithExpiry(fetchConfig.AccountFloorFetch.URL, floorData, cacheExpiry) } @@ -224,7 +224,7 @@ func (f *PriceFloorFetcher) Fetcher() { } case <-f.done: ticker.Stop() - glog.Info("Price Floor fetcher terminated") + logger.Infof("Price Floor fetcher terminated") return } } @@ -233,23 +233,23 @@ func (f *PriceFloorFetcher) Fetcher() { func (f *PriceFloorFetcher) fetchAndValidate(config config.AccountFloorFetch) (*openrtb_ext.PriceFloorRules, int) { floorResp, maxAge, err := f.fetchFloorRulesFromURL(config) if floorResp == nil || err != nil { - glog.Errorf("Error while fetching floor data from URL: %s, reason : %s", config.URL, err.Error()) + logger.Errorf("Error while fetching floor data from URL: %s, reason : %s", config.URL, err.Error()) return nil, 0 } if len(floorResp) > (config.MaxFileSizeKB * 1024) { - glog.Errorf("Received invalid floor data from URL: %s, reason : floor file size is greater than MaxFileSize", config.URL) + logger.Errorf("Received invalid floor data from URL: %s, reason : floor file size is greater than MaxFileSize", config.URL) return nil, 0 } var priceFloors openrtb_ext.PriceFloorRules if err = json.Unmarshal(floorResp, &priceFloors.Data); err != nil { - glog.Errorf("Received invalid price floor json from URL: %s", config.URL) + logger.Errorf("Received invalid price floor json from URL: %s", config.URL) return nil, 0 } if err := validateRules(config, &priceFloors); err != nil { - glog.Errorf("Validation failed for floor JSON from URL: %s, reason: %s", config.URL, err.Error()) + logger.Errorf("Validation failed for floor JSON from URL: %s, reason: %s", config.URL, err.Error()) return nil, 0 } @@ -275,7 +275,7 @@ func (f *PriceFloorFetcher) fetchFloorRulesFromURL(config config.AccountFloorFet // read the entire response body to ensure full connection reuse if there's an // invalid status code if _, err := io.Copy(io.Discard, httpResp.Body); err != nil { - glog.Errorf("error while draining fetched floor response body: %v", err) + logger.Errorf("error while draining fetched floor response body: %v", err) } httpResp.Body.Close() }() @@ -288,10 +288,10 @@ func (f *PriceFloorFetcher) fetchFloorRulesFromURL(config config.AccountFloorFet if maxAgeStr := httpResp.Header.Get("max-age"); maxAgeStr != "" { maxAge, err = strconv.Atoi(maxAgeStr) if err != nil { - glog.Errorf("max-age in header is malformed for url %s", config.URL) + logger.Errorf("max-age in header is malformed for url %s", config.URL) } if maxAge <= config.Period || maxAge > math.MaxInt32 { - glog.Errorf("Invalid max-age = %s provided, value should be valid integer and should be within (%v, %v)", maxAgeStr, config.Period, math.MaxInt32) + logger.Errorf("Invalid max-age = %s provided, value should be valid integer and should be within (%v, %v)", maxAgeStr, config.Period, math.MaxInt32) } } diff --git a/floors/rule.go b/floors/rule.go index 189c765d30..fb3130c609 100644 --- a/floors/rule.go +++ b/floors/rule.go @@ -7,9 +7,9 @@ import ( "sort" "strings" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/currency" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/ptrutil" ) @@ -74,7 +74,7 @@ func getMinFloorValue(floorExt *openrtb_ext.PriceFloorRules, imp *openrtb_ext.Im floorCur = getFloorCurrency(floorExt) if floorMin > 0.0 && floorMinCur != "" { if floorExt.FloorMinCur != "" && impFloorCur != "" && floorExt.FloorMinCur != impFloorCur { - glog.Warning("FloorMinCur are different in floorExt and ImpExt") + logger.Warnf("FloorMinCur are different in floorExt and ImpExt") } if floorCur != "" && floorMinCur != floorCur { rate, err = conversions.GetRate(floorMinCur, floorCur) diff --git a/gdpr/vendorlist-fetching.go b/gdpr/vendorlist-fetching.go index c7b462a259..2a3be433ec 100644 --- a/gdpr/vendorlist-fetching.go +++ b/gdpr/vendorlist-fetching.go @@ -10,11 +10,11 @@ import ( "sync/atomic" "time" - "github.com/golang/glog" "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "golang.org/x/net/context/ctxhttp" ) @@ -119,24 +119,24 @@ func newOccasionalSaver(timeout time.Duration) func(ctx context.Context, client func saveOne(ctx context.Context, client *http.Client, url string, saver saveVendors, me metrics.MetricsEngine) uint16 { req, err := http.NewRequest("GET", url, nil) if err != nil { - glog.Errorf("Failed to build GET %s request. Cookie syncs may be affected: %v", url, err) + logger.Errorf("Failed to build GET %s request. Cookie syncs may be affected: %v", url, err) return 0 } resp, err := ctxhttp.Do(ctx, client, req) if err != nil { - glog.Errorf("Error calling GET %s. Cookie syncs may be affected: %v", url, err) + logger.Errorf("Error calling GET %s. Cookie syncs may be affected: %v", url, err) return 0 } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { - glog.Errorf("Error reading response body from GET %s. Cookie syncs may be affected: %v", url, err) + logger.Errorf("Error reading response body from GET %s. Cookie syncs may be affected: %v", url, err) return 0 } if resp.StatusCode != http.StatusOK { - glog.Errorf("GET %s returned %d. Cookie syncs may be affected.", url, resp.StatusCode) + logger.Errorf("GET %s returned %d. Cookie syncs may be affected.", url, resp.StatusCode) me.RecordGvlListRequest() return 0 } @@ -145,7 +145,7 @@ func saveOne(ctx context.Context, client *http.Client, url string, saver saveVen var newList api.VendorList newList, err = vendorlist2.ParseEagerly(respBody) if err != nil { - glog.Errorf("GET %s returned malformed JSON. Cookie syncs may be affected. Error was %v. Body was %s", url, err, string(respBody)) + logger.Errorf("GET %s returned malformed JSON. Cookie syncs may be affected. Error was %v. Body was %s", url, err, string(respBody)) return 0 } diff --git a/hooks/hookexecution/context.go b/hooks/hookexecution/context.go index 128008001c..75ad2a8217 100644 --- a/hooks/hookexecution/context.go +++ b/hooks/hookexecution/context.go @@ -3,9 +3,9 @@ package hookexecution import ( "sync" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/privacy" ) @@ -30,7 +30,7 @@ func (ctx executionContext) getModuleContext(moduleName string) hookstage.Module if ctx.account != nil { cfg, err := ctx.account.Hooks.Modules.ModuleConfig(moduleName) if err != nil { - glog.Warningf("Failed to get account config for %s module: %s", moduleName, err) + logger.Warnf("Failed to get account config for %s module: %s", moduleName, err) } moduleInvocationCtx.AccountID = ctx.accountID diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go index 182af44dbd..57a145dd1c 100644 --- a/hooks/hookexecution/execution.go +++ b/hooks/hookexecution/execution.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/hooks" "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/ortb" @@ -108,7 +108,7 @@ func executeHook[H any, P any]( go func() { defer func() { if r := recover(); r != nil { - glog.Errorf("OpenRTB auction recovered panic in module hook %s.%s: %v, Stack trace is: %v", + logger.Errorf("OpenRTB auction recovered panic in module hook %s.%s: %v, Stack trace is: %v", hw.Module, hw.Code, r, string(debug.Stack())) } }() diff --git a/hooks/plan.go b/hooks/plan.go index 25dcd8c4b4..c64dfb1cfb 100644 --- a/hooks/plan.go +++ b/hooks/plan.go @@ -3,9 +3,9 @@ package hooks import ( "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/logger" ) type Stage string @@ -210,7 +210,7 @@ func getGroup[T any](getHookFn hookFn[T], cfg config.HookExecutionGroup) Group[T if h, ok := getHookFn(hookCfg.ModuleCode); ok { group.Hooks = append(group.Hooks, HookWrapper[T]{Module: hookCfg.ModuleCode, Code: hookCfg.HookImplCode, Hook: h}) } else { - glog.Warningf("Not found hook while building hook execution plan: %s %s", hookCfg.ModuleCode, hookCfg.HookImplCode) + logger.Warnf("Not found hook while building hook execution plan: %s %s", hookCfg.ModuleCode, hookCfg.HookImplCode) } } diff --git a/logger/glog.go b/logger/glog.go new file mode 100644 index 0000000000..dfeb3530f1 --- /dev/null +++ b/logger/glog.go @@ -0,0 +1,41 @@ +package logger + +import ( + "github.com/golang/glog" +) + +// GlogLogger implements the Logger interface for logging using the glog library with configurable call depth. +type GlogLogger struct { + depth int +} + +// Debug logs a debug-level message with the specified format and arguments. +func (logger *GlogLogger) Debugf(msg string, args ...any) { + glog.InfoDepthf(logger.depth, msg, args...) +} + +// Info logs an informational-level message with the specified format and optional arguments. +func (logger *GlogLogger) Infof(msg string, args ...any) { + glog.InfoDepthf(logger.depth, msg, args...) +} + +// Warn logs a warning-level message with the specified format and arguments. +func (logger *GlogLogger) Warnf(msg string, args ...any) { + glog.WarningDepthf(logger.depth, msg, args...) +} + +// Error logs an error-level message with the specified format and arguments. +func (logger *GlogLogger) Errorf(msg string, args ...any) { + glog.ErrorDepthf(logger.depth, msg, args...) +} + +// Fatal logs a fatal-level message with the specified format and arguments, then exits the application. +func (logger *GlogLogger) Fatalf(msg string, args ...any) { + glog.FatalDepthf(logger.depth, msg, args...) +} + +func NewGlogLogger() Logger { + return &GlogLogger{ + depth: 1, + } +} diff --git a/logger/glog_test.go b/logger/glog_test.go new file mode 100644 index 0000000000..0af2394cb6 --- /dev/null +++ b/logger/glog_test.go @@ -0,0 +1,171 @@ +package logger + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewGlogLogger(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("stderrthreshold", "INFO") + + logger := NewGlogLogger() + + assert.NotNil(t, logger, "NewGlogLogger should return a non-nil logger") + + glogLogger, ok := logger.(*GlogLogger) + assert.True(t, ok, "Logger should be of type *GlogLogger") + assert.Equal(t, 1, glogLogger.depth, "Default depth should be 1") +} + +func TestGlogLogger_ImplementsLoggerInterface(t *testing.T) { + var _ Logger = (*GlogLogger)(nil) +} + +func TestGlogLogger_Debug(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("v", "2") + + logger := NewGlogLogger() + + // This test verifies the method can be called without panicking + // Actual log output verification would require capturing stderr + assert.NotPanics(t, func() { + logger.Debugf("debug message") + }, "Debug should not panic") + + assert.NotPanics(t, func() { + logger.Debugf("debug message with args: %s, %d", "test", 123) + }, "Debug with args should not panic") +} + +func TestGlogLogger_Info(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + assert.NotPanics(t, func() { + logger.Infof("info message") + }, "Info should not panic") + + assert.NotPanics(t, func() { + logger.Infof("info message with args: %s, %d", "test", 456) + }, "Info with args should not panic") +} + +func TestGlogLogger_Warn(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + assert.NotPanics(t, func() { + logger.Warnf("warning message") + }, "Warn should not panic") + + assert.NotPanics(t, func() { + logger.Warnf("warning message with args: %s, %d", "test", 789) + }, "Warn with args should not panic") +} + +func TestGlogLogger_Error(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + assert.NotPanics(t, func() { + logger.Errorf("error message") + }, "Error should not panic") + + assert.NotPanics(t, func() { + logger.Errorf("error message with args: %s, %d", "test", 999) + }, "Error with args should not panic") +} + +func TestGlogLogger_AllLevels(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("v", "2") + + logger := NewGlogLogger() + + // Test that all logging levels work together + assert.NotPanics(t, func() { + logger.Debugf("debug") + logger.Infof("info") + logger.Warnf("warn") + logger.Errorf("error") + }, "All logging levels should work without panic") +} + +func TestGlogLogger_Depth(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + glogLogger := &GlogLogger{depth: 2} + + // Test with custom depth + assert.NotPanics(t, func() { + glogLogger.Infof("info with custom depth") + }, "Logger with custom depth should not panic") +} + +func TestGlogLogger_EmptyMessage(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + // Test with empty messages + assert.NotPanics(t, func() { + logger.Infof("") + logger.Debugf("") + logger.Warnf("") + logger.Errorf("") + }, "Empty messages should not panic") +} + +func TestGlogLogger_NoArgs(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + // Test logging without variadic args + assert.NotPanics(t, func() { + logger.Infof("simple message") + logger.Debugf("simple debug") + logger.Warnf("simple warning") + logger.Errorf("simple error") + }, "Messages without args should not panic") +} + +func TestGlogLogger_MultipleArgs(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + // Test with multiple arguments + assert.NotPanics(t, func() { + logger.Infof("message: %s, number: %d, float: %f, bool: %v", "test", 42, 3.14, true) + }, "Messages with multiple args should not panic") +} + +func TestGlogLogger_SpecialCharacters(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + logger := NewGlogLogger() + + // Test with special characters + assert.NotPanics(t, func() { + logger.Infof("message with special chars: \n\t\"quotes\" and 'apostrophes'") + }, "Messages with special characters should not panic") +} diff --git a/logger/interface.go b/logger/interface.go new file mode 100644 index 0000000000..4d840381bf --- /dev/null +++ b/logger/interface.go @@ -0,0 +1,18 @@ +package logger + +type Logger interface { + // Debugf level logging + Debugf(msg string, args ...any) + + // Infof level logging + Infof(msg string, args ...any) + + // Warnf level logging + Warnf(msg string, args ...any) + + // Errorf level logging + Errorf(msg string, args ...any) + + // Fatalf level logging + Fatalf(msg string, args ...any) +} diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000000..ecaf46e1c4 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,28 @@ +package logger + +var logger Logger = NewGlogLogger() + +// Debugf level logging +func Debugf(msg string, args ...any) { + logger.Debugf(msg, args...) +} + +// Infof level logging +func Infof(msg string, args ...any) { + logger.Infof(msg, args...) +} + +// Warnf level logging +func Warnf(msg string, args ...any) { + logger.Warnf(msg, args...) +} + +// Errorf level logging +func Errorf(msg string, args ...any) { + logger.Errorf(msg, args...) +} + +// Fatalf level logging and terminates the program execution. +func Fatalf(msg string, args ...any) { + logger.Fatalf(msg, args...) +} diff --git a/logger/logger_test.go b/logger/logger_test.go new file mode 100644 index 0000000000..1b7f285e9f --- /dev/null +++ b/logger/logger_test.go @@ -0,0 +1,304 @@ +package logger + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +// mockLogger is a test implementation of the Logger interface +type mockLogger struct { + debugCalls []logCall + infoCalls []logCall + warnCalls []logCall + errorCalls []logCall + fatalCalls []logCall +} + +type logCall struct { + msg string + args []any +} + +func (m *mockLogger) Debugf(msg string, args ...any) { + m.debugCalls = append(m.debugCalls, logCall{msg, args}) +} + +func (m *mockLogger) Infof(msg string, args ...any) { + m.infoCalls = append(m.infoCalls, logCall{msg, args}) +} + +func (m *mockLogger) Warnf(msg string, args ...any) { + m.warnCalls = append(m.warnCalls, logCall{msg, args}) +} + +func (m *mockLogger) Errorf(msg string, args ...any) { + m.errorCalls = append(m.errorCalls, logCall{msg, args}) +} + +func (m *mockLogger) Fatalf(msg string, args ...any) { + m.fatalCalls = append(m.fatalCalls, logCall{msg, args}) +} + +func newMockLogger() *mockLogger { + return &mockLogger{ + debugCalls: []logCall{}, + infoCalls: []logCall{}, + warnCalls: []logCall{}, + errorCalls: []logCall{}, + fatalCalls: []logCall{}, + } +} + +func TestDefaultLogger(t *testing.T) { + // The default logger should be GlogLogger + defaultLogger := logger + assert.NotNil(t, defaultLogger, "Default logger should not be nil") + + _, ok := defaultLogger.(*GlogLogger) + assert.True(t, ok, "Default logger should be *GlogLogger") +} + +func TestDebug(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("v", "2") + + mock := newMockLogger() + logger = mock + + Debugf("debug message") + assert.Len(t, mock.debugCalls, 1, "Should have one debug call") + assert.Equal(t, "debug message", mock.debugCalls[0].msg) + assert.Empty(t, mock.debugCalls[0].args) + + Debugf("debug with args: %s, %d", "test", 123) + assert.Len(t, mock.debugCalls, 2, "Should have two debug calls") + assert.Equal(t, "debug with args: %s, %d", mock.debugCalls[1].msg) + assert.Equal(t, []any{"test", 123}, mock.debugCalls[1].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestInfo(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Infof("info message") + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Equal(t, "info message", mock.infoCalls[0].msg) + assert.Empty(t, mock.infoCalls[0].args) + + Infof("info with args: %s, %d", "test", 456) + assert.Len(t, mock.infoCalls, 2, "Should have two info calls") + assert.Equal(t, "info with args: %s, %d", mock.infoCalls[1].msg) + assert.Equal(t, []any{"test", 456}, mock.infoCalls[1].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestWarn(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Warnf("warning message") + assert.Len(t, mock.warnCalls, 1, "Should have one warn call") + assert.Equal(t, "warning message", mock.warnCalls[0].msg) + assert.Empty(t, mock.warnCalls[0].args) + + Warnf("warning with args: %s, %d", "test", 789) + assert.Len(t, mock.warnCalls, 2, "Should have two warn calls") + assert.Equal(t, "warning with args: %s, %d", mock.warnCalls[1].msg) + assert.Equal(t, []any{"test", 789}, mock.warnCalls[1].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestError(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Errorf("error message") + assert.Len(t, mock.errorCalls, 1, "Should have one error call") + assert.Equal(t, "error message", mock.errorCalls[0].msg) + assert.Empty(t, mock.errorCalls[0].args) + + Errorf("error with args: %s, %d", "test", 999) + assert.Len(t, mock.errorCalls, 2, "Should have two error calls") + assert.Equal(t, "error with args: %s, %d", mock.errorCalls[1].msg) + assert.Equal(t, []any{"test", 999}, mock.errorCalls[1].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestAllLogLevels(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("v", "2") + + mock := newMockLogger() + logger = mock + + Debugf("debug") + Infof("info") + Warnf("warn") + Errorf("error") + Fatalf("fatal") + + assert.Len(t, mock.debugCalls, 1, "Should have one debug call") + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Len(t, mock.warnCalls, 1, "Should have one warn call") + assert.Len(t, mock.errorCalls, 1, "Should have one error call") + assert.Len(t, mock.fatalCalls, 1, "Should have one fatal call") + + // Restore default logger + logger = NewGlogLogger() +} + +func TestEmptyMessages(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Debugf("") + Infof("") + Warnf("") + Errorf("") + Fatalf("") + + assert.Len(t, mock.debugCalls, 1, "Should have one debug call") + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Len(t, mock.warnCalls, 1, "Should have one warn call") + assert.Len(t, mock.errorCalls, 1, "Should have one error call") + assert.Len(t, mock.fatalCalls, 1, "Should have one fatal call") + + assert.Equal(t, "", mock.debugCalls[0].msg) + assert.Equal(t, "", mock.infoCalls[0].msg) + assert.Equal(t, "", mock.warnCalls[0].msg) + assert.Equal(t, "", mock.errorCalls[0].msg) + assert.Equal(t, "", mock.fatalCalls[0].msg) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestMultipleArguments(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Infof("message: %s, number: %d, float: %f, bool: %v", "test", 42, 3.14, true) + + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Equal(t, "message: %s, number: %d, float: %f, bool: %v", mock.infoCalls[0].msg) + assert.Equal(t, []any{"test", 42, 3.14, true}, mock.infoCalls[0].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestNoArgs(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Infof("simple message") + Debugf("simple debug") + Warnf("simple warning") + Errorf("simple error") + Fatalf("simple fatal") + + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Len(t, mock.debugCalls, 1, "Should have one debug call") + assert.Len(t, mock.warnCalls, 1, "Should have one warn call") + assert.Len(t, mock.errorCalls, 1, "Should have one error call") + assert.Len(t, mock.fatalCalls, 1, "Should have one fatal call") + + assert.Empty(t, mock.infoCalls[0].args) + assert.Empty(t, mock.debugCalls[0].args) + assert.Empty(t, mock.warnCalls[0].args) + assert.Empty(t, mock.errorCalls[0].args) + assert.Empty(t, mock.fatalCalls[0].args) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestWithRealGlogLogger(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + flag.Set("v", "2") + + // Use real GlogLogger + logger = NewGlogLogger() + + // These should not panic + assert.NotPanics(t, func() { + Debugf("debug message") + Infof("info message") + Warnf("warning message") + Errorf("error message") + }, "Real GlogLogger should not panic") +} + +func TestSpecialCharacters(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Infof("message with special chars: \n\t\"quotes\" and 'apostrophes'") + + assert.Len(t, mock.infoCalls, 1, "Should have one info call") + assert.Equal(t, "message with special chars: \n\t\"quotes\" and 'apostrophes'", mock.infoCalls[0].msg) + + // Restore default logger + logger = NewGlogLogger() +} + +func TestLoggerInterfaceCompliance(t *testing.T) { + var _ Logger = (*mockLogger)(nil) + var _ Logger = (*GlogLogger)(nil) +} + +func TestFatal(t *testing.T) { + // Initialize glog flags + flag.Set("logtostderr", "true") + + mock := newMockLogger() + logger = mock + + Fatalf("fatal message") + assert.Len(t, mock.fatalCalls, 1, "Should have one fatal call") + assert.Equal(t, "fatal message", mock.fatalCalls[0].msg) + assert.Empty(t, mock.fatalCalls[0].args) + + Fatalf("fatal with args: %s, %d", "test", 111) + assert.Len(t, mock.fatalCalls, 2, "Should have two fatal calls") + assert.Equal(t, "fatal with args: %s, %d", mock.fatalCalls[1].msg) + assert.Equal(t, []any{"test", 111}, mock.fatalCalls[1].args) + + // Restore default logger + logger = NewGlogLogger() +} diff --git a/main.go b/main.go index 5e0f5cfd33..dbc2d91f10 100644 --- a/main.go +++ b/main.go @@ -10,13 +10,13 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/currency" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/router" "github.com/prebid/prebid-server/v3/server" "github.com/prebid/prebid-server/v3/util/jsonutil" "github.com/prebid/prebid-server/v3/util/task" - "github.com/golang/glog" "github.com/spf13/viper" ) @@ -29,16 +29,17 @@ func main() { bidderInfoPath, err := filepath.Abs(infoDirectory) if err != nil { - glog.Exitf("Unable to build configuration directory path: %v", err) + logger.Fatalf("Unable to build configuration directory path: %v", err) } bidderInfos, err := config.LoadBidderInfoFromDisk(bidderInfoPath) if err != nil { - glog.Exitf("Unable to load bidder configurations: %v", err) + logger.Fatalf("Unable to load bidder configurations: %v", err) } + cfg, err := loadConfig(bidderInfos) if err != nil { - glog.Exitf("Configuration could not be loaded or did not pass validation: %v", err) + logger.Fatalf("Configuration could not be loaded or did not pass validation: %v", err) } // Create a soft memory limit on the total amount of memory that PBS uses to tune the behavior @@ -51,7 +52,7 @@ func main() { err = serve(cfg) if err != nil { - glog.Exitf("prebid-server failed: %v", err) + logger.Fatalf("prebid-server failed: %v", err) } } @@ -80,7 +81,7 @@ func serve(cfg *config.Configuration) error { corsRouter := router.SupportCORS(r) if err := server.Listen(cfg, router.NoCache{Handler: corsRouter}, router.Admin(currencyConverter, fetchingInterval), r.MetricsEngine); err != nil { - glog.Fatalf("prebid-server returned an error: %v", err) + logger.Fatalf("prebid-server returned an error: %v", err) } r.Shutdown() diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index 2be2675272..aa64e41a8d 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/openrtb_ext" metrics "github.com/rcrowley/go-metrics" ) @@ -719,7 +719,7 @@ func (me *Metrics) RecordAdapterPanic(labels AdapterLabels) { lowerCaseAdapterName := strings.ToLower(adapterStr) am, ok := me.AdapterMetrics[lowerCaseAdapterName] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } am.PanicMeter.Mark(1) @@ -731,7 +731,7 @@ func (me *Metrics) RecordAdapterRequest(labels AdapterLabels) { lowerCaseAdapter := strings.ToLower(adapterStr) am, ok := me.AdapterMetrics[lowerCaseAdapter] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } @@ -748,7 +748,7 @@ func (me *Metrics) RecordAdapterRequest(labels AdapterLabels) { aam.GotBidsMeter.Mark(1) } default: - glog.Warningf("No go-metrics logged for AdapterBids value: %s", labels.AdapterBids) + logger.Warnf("No go-metrics logged for AdapterBids value: %s", labels.AdapterBids) } for errType := range labels.AdapterErrors { am.ErrorMeters[errType].Mark(1) @@ -771,7 +771,7 @@ func (me *Metrics) RecordAdapterConnections(adapterName openrtb_ext.BidderName, lowerCaseAdapterName := strings.ToLower(string(adapterName)) am, ok := me.AdapterMetrics[lowerCaseAdapterName] if !ok { - glog.Errorf("Trying to log adapter connection metrics for %s: adapter not found", string(adapterName)) + logger.Errorf("Trying to log adapter connection metrics for %s: adapter not found", string(adapterName)) return } @@ -810,7 +810,7 @@ func (me *Metrics) RecordAdapterBidReceived(labels AdapterLabels, bidType openrt lowerCaseAdapterName := strings.ToLower(adapterStr) am, ok := me.AdapterMetrics[lowerCaseAdapterName] if !ok { - glog.Errorf("Trying to run adapter bid metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter bid metrics on %s: adapter metrics not found", adapterStr) return } @@ -828,7 +828,7 @@ func (me *Metrics) RecordAdapterBidReceived(labels AdapterLabels, bidType openrt metricsForType.NurlMeter.Mark(1) } } else { - glog.Errorf("bid/adm metrics map entry does not exist for type %s. This is a bug, and should be reported.", bidType) + logger.Errorf("bid/adm metrics map entry does not exist for type %s. This is a bug, and should be reported.", bidType) } } @@ -838,7 +838,7 @@ func (me *Metrics) RecordAdapterPrice(labels AdapterLabels, cpm float64) { lowercaseAdapter := strings.ToLower(adapterStr) am, ok := me.AdapterMetrics[lowercaseAdapter] if !ok { - glog.Errorf("Trying to run adapter price metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter price metrics on %s: adapter metrics not found", adapterStr) return } // Adapter metrics @@ -855,7 +855,7 @@ func (me *Metrics) RecordAdapterTime(labels AdapterLabels, length time.Duration) lowercaseAdapter := strings.ToLower(adapterStr) am, ok := me.AdapterMetrics[lowercaseAdapter] if !ok { - glog.Errorf("Trying to run adapter latency metrics on %s: adapter metrics not found", string(labels.Adapter)) + logger.Errorf("Trying to run adapter latency metrics on %s: adapter metrics not found", string(labels.Adapter)) return } // Adapter metrics @@ -981,7 +981,7 @@ func (me *Metrics) RecordAdapterBuyerUIDScrubbed(adapterName openrtb_ext.BidderN am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to log adapter buyeruid scrubbed metric for %s: adapter not found", adapterStr) + logger.Errorf("Trying to log adapter buyeruid scrubbed metric for %s: adapter not found", adapterStr) return } @@ -996,7 +996,7 @@ func (me *Metrics) RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.Bidde am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to log adapter GDPR request blocked metric for %s: adapter not found", adapterStr) + logger.Errorf("Trying to log adapter GDPR request blocked metric for %s: adapter not found", adapterStr) return } @@ -1019,7 +1019,7 @@ func (me *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.Bidd adapterStr := string(adapter) am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } am.BidValidationCreativeSizeErrorMeter.Mark(1) @@ -1034,7 +1034,7 @@ func (me *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.Bidde adapterStr := string(adapter) am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } am.BidValidationCreativeSizeWarnMeter.Mark(1) @@ -1049,7 +1049,7 @@ func (me *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.Bidd adapterStr := string(adapter) am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } am.BidValidationSecureMarkupErrorMeter.Mark(1) @@ -1064,7 +1064,7 @@ func (me *Metrics) RecordBidValidationSecureMarkupWarn(adapter openrtb_ext.Bidde adapterStr := string(adapter) am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) + logger.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr) return } am.BidValidationSecureMarkupWarnMeter.Mark(1) @@ -1200,7 +1200,7 @@ func (me *Metrics) getModuleMetric(labels ModuleLabels) (*ModuleMetrics, error) mm, ok := me.ModuleMetrics[labels.Module][labels.Stage] if !ok { err := fmt.Errorf("Trying to run module %s metrics for stage %s: module metrics not found", labels.Module, labels.Stage) - glog.Errorf(err.Error()) + logger.Errorf("%v", err) return nil, err } @@ -1211,7 +1211,7 @@ func (me *Metrics) RecordAdapterThrottled(adapterName openrtb_ext.BidderName) { adapterStr := adapterName.String() am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)] if !ok { - glog.Errorf("Trying to log adapter throttled metric for %s: adapter not found", adapterStr) + logger.Errorf("Trying to log adapter throttled metric for %s: adapter not found", adapterStr) return } diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go index 5f70ad5849..d16ac64f07 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go @@ -6,7 +6,7 @@ import ( "fmt" "strconv" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) // deviceInfoExtractor is a struct that contains the methods to extract device information @@ -104,18 +104,18 @@ func (x deviceInfoExtractor) getValue(results Results, propertyName deviceInfoPr ",", ) if err != nil { - glog.Errorf("Failed to get results values string.") + logger.Errorf("Failed to get results values string.") return "" } hasValues, err := results.HasValues(string(propertyName)) if err != nil { - glog.Errorf("Failed to check if a matched value exists for property %s.\n", propertyName) + logger.Errorf("Failed to check if a matched value exists for property %s.\n", propertyName) return "" } if !hasValues { - glog.Warningf("Property %s does not have a matched value.\n", propertyName) + logger.Warnf("Property %s does not have a matched value.\n", propertyName) return "Unknown" } diff --git a/modules/modules.go b/modules/modules.go index 59c3c0f3a7..fc2e15e7ef 100644 --- a/modules/modules.go +++ b/modules/modules.go @@ -4,9 +4,9 @@ import ( "encoding/json" "fmt" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/hooks" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/modules/moduledeps" "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -71,7 +71,7 @@ func (m *builder) Build( } if !isEnabled { - glog.Infof("Skip %s module, disabled.", id) + logger.Infof("Skip %s module, disabled.", id) continue } diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go index e4c19380b2..15fab4fc68 100644 --- a/modules/scope3/rtd/module.go +++ b/modules/scope3/rtd/module.go @@ -18,11 +18,11 @@ import ( "time" "github.com/coocood/freecache" - "github.com/golang/glog" jsoniter "github.com/json-iterator/go" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/hooks/hookanalytics" "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/modules/moduledeps" "github.com/prebid/prebid-server/v3/util/iterutil" "github.com/prebid/prebid-server/v3/util/jsonutil" @@ -447,7 +447,7 @@ func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.B // Cache the result err = m.cache.Set(cacheKey, []byte(strings.Join(segments, ",")), m.cfg.CacheTTL) if err != nil { - glog.Infof("could not set segments in cache: %v", err) + logger.Infof("could not set segments in cache: %v", err) } return segments, nil diff --git a/modules/shutdown.go b/modules/shutdown.go index 49fabadfc9..ae769ddf5e 100644 --- a/modules/shutdown.go +++ b/modules/shutdown.go @@ -1,7 +1,7 @@ package modules import ( - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) // Shutdowner is an interface that defines a method for shutting down modules. @@ -33,7 +33,7 @@ func NewShutdownModules(modules map[string]interface{}) *ShutdownModules { func (s *ShutdownModules) Shutdown() { for _, module := range s.modules { if err := module.Shutdown(); err != nil { - glog.Errorf("Error shutting down module: %v", err) + logger.Errorf("Error shutting down module: %v", err) } } return diff --git a/pbs/usersync.go b/pbs/usersync.go index bd99eb7d10..2a88ecc7b9 100644 --- a/pbs/usersync.go +++ b/pbs/usersync.go @@ -10,9 +10,9 @@ import ( "net/url" "strings" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/usersync" ) @@ -51,7 +51,7 @@ func (deps *UserSyncDeps) VerifyRecaptcha(response string) error { // read the entire response body to ensure full connection reuse if there's an // error while decoding the json if _, err := io.Copy(io.Discard, resp.Body); err != nil { - glog.Errorf("Captcha verify draining response body failed: %v", err) + logger.Errorf("Captcha verify draining response body failed: %v", err) } resp.Body.Close() }() @@ -79,9 +79,7 @@ func (deps *UserSyncDeps) OptOut(w http.ResponseWriter, r *http.Request, _ httpr err := deps.VerifyRecaptcha(rr) if err != nil { - if glog.V(2) { - glog.Infof("Opt Out failed recaptcha: %v", err) - } + logger.Infof("Opt Out failed recaptcha: %v", err) w.WriteHeader(http.StatusUnauthorized) return } diff --git a/prebid_cache_client/client.go b/prebid_cache_client/client.go index c0a7ff83eb..adc57b97ad 100644 --- a/prebid_cache_client/client.go +++ b/prebid_cache_client/client.go @@ -13,10 +13,10 @@ import ( "time" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/buger/jsonparser" - "github.com/golang/glog" "golang.org/x/net/context/ctxhttp" ) @@ -150,7 +150,7 @@ func (c *clientImpl) PutJson(ctx context.Context, values []Cacheable) (uuids []s func logError(errs *[]error, format string, a ...interface{}) { msg := fmt.Sprintf(format, a...) - glog.Error(msg) + logger.Errorf(msg) *errs = append(*errs, errors.New(msg)) } diff --git a/router/router.go b/router/router.go index c7db28ad96..87e88324c9 100644 --- a/router/router.go +++ b/router/router.go @@ -25,6 +25,7 @@ import ( "github.com/prebid/prebid-server/v3/floors" "github.com/prebid/prebid-server/v3/gdpr" "github.com/prebid/prebid-server/v3/hooks" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/macros" "github.com/prebid/prebid-server/v3/metrics" metricsConf "github.com/prebid/prebid-server/v3/metrics/config" @@ -43,7 +44,6 @@ import ( "github.com/prebid/prebid-server/v3/version" _ "github.com/go-sql-driver/mysql" - "github.com/golang/glog" "github.com/julienschmidt/httprouter" _ "github.com/lib/pq" "github.com/rs/cors" @@ -67,7 +67,7 @@ func newJsonDirectoryServer(schemaDirectory string, validator openrtb_ext.Bidder // Slurp the files into memory first, since they're small and it minimizes request latency. files, err := os.ReadDir(schemaDirectory) if err != nil { - glog.Fatalf("Failed to read directory %s: %v", schemaDirectory, err) + logger.Fatalf("Failed to read directory %s: %v", schemaDirectory, err) } bidderMap := openrtb_ext.BuildBidderMap() @@ -77,7 +77,7 @@ func newJsonDirectoryServer(schemaDirectory string, validator openrtb_ext.Bidder bidder := strings.TrimSuffix(file.Name(), ".json") bidderName, isValid := bidderMap[bidder] if !isValid { - glog.Fatalf("Schema exists for an unknown bidder: %s", bidder) + logger.Fatalf("Schema exists for an unknown bidder: %s", bidder) } data[bidder] = json.RawMessage(validator.Schema(bidderName)) } @@ -89,7 +89,7 @@ func newJsonDirectoryServer(schemaDirectory string, validator openrtb_ext.Bidder response, err := jsonutil.Marshal(data) if err != nil { - glog.Fatalf("Failed to marshal bidder param JSON-schema: %v", err) + logger.Fatalf("Failed to marshal bidder param JSON-schema: %v", err) } return func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { @@ -132,13 +132,13 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R // local file system certPool, certPoolCreateErr := ssl.CreateCertPool(cfg.CertsUseSystem) if certPoolCreateErr != nil { - glog.Infof("Could not load root certificates: %s \n", certPoolCreateErr.Error()) + logger.Infof("Could not load root certificates: %s \n", certPoolCreateErr.Error()) } var readCertErr error certPool, readCertErr = ssl.AppendPEMFileToRootCAPool(certPool, cfg.PemCertsFile) if readCertErr != nil { - glog.Infof("Could not read certificates file: %s \n", readCertErr.Error()) + logger.Infof("Could not read certificates file: %s \n", readCertErr.Error()) } generalHttpClient := &http.Client{ @@ -212,7 +212,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R moduleDeps := moduledeps.ModuleDeps{HTTPClient: generalHttpClient, RateConvertor: rateConvertor, Geoscope: normalizedGeoscopes} repo, moduleStageNames, shutdownModules, err := modules.NewBuilder().Build(cfg.Hooks.Modules, moduleDeps) if err != nil { - glog.Fatalf("Failed to init hook modules: %v", err) + logger.Fatalf("Failed to init hook modules: %v", err) } // Metrics engine @@ -226,7 +226,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R paramsValidator, err := openrtb_ext.NewBidderParamsValidator(schemaDirectory) if err != nil { - glog.Fatalf("Failed to create the bidder params validator. %v", err) + logger.Fatalf("Failed to create the bidder params validator. %v", err) } activeBidders := exchange.GetActiveBidders(cfg.BidderInfos) @@ -248,7 +248,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R } adsCertSigner, err := adscert.NewAdCertsSigner(cfg.Experiment.AdCerts) if err != nil { - glog.Fatalf("Failed to create ads cert signer: %v", err) + logger.Fatalf("Failed to create ads cert signer: %v", err) } requestValidator := ortb.NewRequestValidator(activeBidders, disabledBidders, paramsValidator) @@ -261,17 +261,17 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R var uuidGenerator uuidutil.UUIDRandomGenerator openrtbEndpoint, err := openrtb2.NewEndpoint(uuidGenerator, theExchange, requestValidator, fetcher, accounts, cfg, r.MetricsEngine, analyticsRunner, disabledBidders, defReqJSON, activeBidders, storedRespFetcher, planBuilder, tmaxAdjustments) if err != nil { - glog.Fatalf("Failed to create the openrtb2 endpoint handler. %v", err) + logger.Fatalf("Failed to create the openrtb2 endpoint handler. %v", err) } ampEndpoint, err := openrtb2.NewAmpEndpoint(uuidGenerator, theExchange, requestValidator, ampFetcher, accounts, cfg, r.MetricsEngine, analyticsRunner, disabledBidders, defReqJSON, activeBidders, storedRespFetcher, planBuilder, tmaxAdjustments) if err != nil { - glog.Fatalf("Failed to create the amp endpoint handler. %v", err) + logger.Fatalf("Failed to create the amp endpoint handler. %v", err) } videoEndpoint, err := openrtb2.NewVideoEndpoint(uuidGenerator, theExchange, requestValidator, fetcher, videoFetcher, accounts, cfg, r.MetricsEngine, analyticsRunner, disabledBidders, defReqJSON, activeBidders, cacheClient, tmaxAdjustments) if err != nil { - glog.Fatalf("Failed to create the video endpoint handler. %v", err) + logger.Fatalf("Failed to create the video endpoint handler. %v", err) } requestTimeoutHeaders := config.RequestTimeoutHeaders{} @@ -324,11 +324,11 @@ func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, strin // Shutdown closes any dependencies of the router that may need closing func (r *Router) Shutdown() { - glog.Info("[PBS Router] shutting down") + logger.Infof("[PBS Router] shutting down") for _, shutdown := range r.shutdowns { shutdown() } - glog.Info("[PBS Router] shut down") + logger.Infof("[PBS Router] shut down") } func checkSupportedUserSyncEndpoints(bidderInfos config.BidderInfos) error { @@ -342,11 +342,11 @@ func checkSupportedUserSyncEndpoints(bidderInfos config.BidderInfos) error { switch endpointLower { case "iframe": if info.Syncer.IFrame == nil { - glog.Warningf("bidder %s supports iframe user sync, but doesn't have a default and must be configured by the host", name) + logger.Warnf("bidder %s supports iframe user sync, but doesn't have a default and must be configured by the host", name) } case "redirect": if info.Syncer.Redirect == nil { - glog.Warningf("bidder %s supports redirect user sync, but doesn't have a default and must be configured by the host", name) + logger.Warnf("bidder %s supports redirect user sync, but doesn't have a default and must be configured by the host", name) } default: return fmt.Errorf("failed to load bidder info for %s, user sync supported endpoint '%s' is unrecognized", name, endpoint) @@ -397,13 +397,13 @@ func readDefaultRequestFromFile(defReqConfig config.DefReqConfig) []byte { defaultRequestJSON, err := os.ReadFile(defReqConfig.FileSystem.FileName) if err != nil { - glog.Fatalf("error reading default request from file %s: %v", defReqConfig.FileSystem.FileName, err) + logger.Fatalf("error reading default request from file %s: %v", defReqConfig.FileSystem.FileName, err) return []byte{} } // validate json is valid if err := jsonutil.UnmarshalValid(defaultRequestJSON, &openrtb2model.BidRequest{}); err != nil { - glog.Fatalf("error parsing default request from file %s: %v", defReqConfig.FileSystem.FileName, err) + logger.Fatalf("error parsing default request from file %s: %v", defReqConfig.FileSystem.FileName, err) return []byte{} } diff --git a/server/listener.go b/server/listener.go index 3bc1f2e66f..ece1a6ec3d 100644 --- a/server/listener.go +++ b/server/listener.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" ) @@ -31,7 +31,7 @@ func (l *monitorableConnection) Close() error { // in the core Go libs: https://github.com/golang/go/issues/4373#issuecomment-347680321 errString := err.Error() if !strings.Contains(errString, "use of closed network connection") { - glog.Errorf("Error closing connection: %s", errString) + logger.Errorf("Error closing connection: %s", errString) } l.metrics.RecordConnectionClose(false) } @@ -41,7 +41,7 @@ func (l *monitorableConnection) Close() error { func (ln *monitorableListener) Accept() (net.Conn, error) { tc, err := ln.Listener.Accept() if err != nil { - glog.Errorf("Error accepting connection: %v", err) + logger.Errorf("Error accepting connection: %v", err) ln.metrics.RecordConnectionAccept(false) return tc, err } diff --git a/server/prometheus.go b/server/prometheus.go index 98409e6a58..332eebdd1c 100644 --- a/server/prometheus.go +++ b/server/prometheus.go @@ -1,21 +1,21 @@ package server import ( + "fmt" "net/http" "strconv" - "github.com/golang/glog" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" metricsconfig "github.com/prebid/prebid-server/v3/metrics/config" + "github.com/prometheus/client_golang/prometheus/promhttp" ) func newPrometheusServer(cfg *config.Configuration, metrics *metricsconfig.DetailedMetricsEngine) *http.Server { proMetrics := metrics.PrometheusMetrics if proMetrics == nil { - glog.Fatal("Prometheus metrics configured, but a Prometheus metrics engine was not found. Cannot set up a Prometheus listener.") + logger.Fatalf("Prometheus metrics configured, but a Prometheus metrics engine was not found. Cannot set up a Prometheus listener.") } return &http.Server{ Addr: cfg.Host + ":" + strconv.Itoa(cfg.Metrics.Prometheus.Port), @@ -30,5 +30,5 @@ func newPrometheusServer(cfg *config.Configuration, metrics *metricsconfig.Detai type loggerForPrometheus struct{} func (loggerForPrometheus) Println(v ...interface{}) { - glog.Warningln(v...) + logger.Warnf(fmt.Sprintln(v...)) } diff --git a/server/server.go b/server/server.go index 257ccea882..f46fdc8cfe 100644 --- a/server/server.go +++ b/server/server.go @@ -12,8 +12,8 @@ import ( "time" "github.com/NYTimes/gziphandler" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" metricsconfig "github.com/prebid/prebid-server/v3/metrics/config" ) @@ -37,7 +37,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H ) go shutdownAfterSignals(mainServer, stopMain, done) if socketListener, err = newUnixListener(mainServer.Addr, metrics); err != nil { - glog.Errorf("Error listening for Unix-Socket connections on path %s: %v for socket server", mainServer.Addr, err) + logger.Errorf("Error listening for Unix-Socket connections on path %s: %v for socket server", mainServer.Addr, err) return } go runServer(mainServer, "UnixSocket", socketListener) @@ -48,7 +48,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H ) go shutdownAfterSignals(mainServer, stopMain, done) if mainListener, err = newTCPListener(mainServer.Addr, metrics); err != nil { - glog.Errorf("Error listening for TCP connections on %s: %v for main server", mainServer.Addr, err) + logger.Errorf("Error listening for TCP connections on %s: %v for main server", mainServer.Addr, err) return } go runServer(mainServer, "Main", mainListener) @@ -61,7 +61,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H var adminListener net.Listener if adminListener, err = newTCPListener(adminServer.Addr, nil); err != nil { - glog.Errorf("Error listening for TCP connections on %s: %v for admin server", adminServer.Addr, err) + logger.Errorf("Error listening for TCP connections on %s: %v for admin server", adminServer.Addr, err) return } go runServer(adminServer, "Admin", adminListener) @@ -75,7 +75,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H stopChannels = append(stopChannels, stopPrometheus) go shutdownAfterSignals(prometheusServer, stopPrometheus, done) if prometheusListener, err = newTCPListener(prometheusServer.Addr, nil); err != nil { - glog.Errorf("Error listening for TCP connections on %s: %v for prometheus server", prometheusServer.Addr, err) + logger.Errorf("Error listening for TCP connections on %s: %v for prometheus server", prometheusServer.Addr, err) return } @@ -127,17 +127,17 @@ func getCompressionEnabledHandler(h http.Handler, compressionInfo config.Compres func runServer(server *http.Server, name string, listener net.Listener) (err error) { if server == nil { err = fmt.Errorf(">> Server is a nil_ptr.") - glog.Errorf("%s server quit with error: %v", name, err) + logger.Errorf("%s server quit with error: %v", name, err) return } else if listener == nil { err = fmt.Errorf(">> Listener is a nil.") - glog.Errorf("%s server quit with error: %v", name, err) + logger.Errorf("%s server quit with error: %v", name, err) return } - glog.Infof("%s server starting on: %s", name, server.Addr) + logger.Infof("%s server starting on: %s", name, server.Addr) if err = server.Serve(listener); err != nil { - glog.Errorf("%s server quit with error: %v", name, err) + logger.Errorf("%s server quit with error: %v", name, err) } return } @@ -152,7 +152,7 @@ func newTCPListener(address string, metrics metrics.MetricsEngine) (net.Listener if casted, ok := ln.(*net.TCPListener); ok { ln = &tcpKeepAliveListener{casted} } else { - glog.Warning("net.Listen(\"tcp\", \"addr\") didn't return a TCPListener as it did in Go 1.9. Things will probably work fine... but this should be investigated.") + logger.Warnf("net.Listen(\"tcp\", \"addr\") didn't return a TCPListener as it did in Go 1.9. Things will probably work fine... but this should be investigated.") } if metrics != nil { @@ -171,7 +171,7 @@ func newUnixListener(address string, metrics metrics.MetricsEngine) (net.Listene if casted, ok := ln.(*net.UnixListener); ok { ln = &unixListener{casted} } else { - glog.Warning("net.Listen(\"unix\", \"addr\") didn't return an UnixListener.") + logger.Warnf("net.Listen(\"unix\", \"addr\") didn't return an UnixListener.") } if metrics != nil { @@ -200,9 +200,9 @@ func shutdownAfterSignals(server *http.Server, stopper <-chan os.Signal, done ch defer cancel() var s struct{} - glog.Infof("Stopping %s because of signal: %s", server.Addr, sig.String()) + logger.Infof("Stopping %s because of signal: %s", server.Addr, sig.String()) if err := server.Shutdown(ctx); err != nil { - glog.Errorf("Failed to shutdown %s: %v", server.Addr, err) + logger.Errorf("Failed to shutdown %s: %v", server.Addr, err) } done <- s } diff --git a/stored_requests/backends/db_fetcher/fetcher.go b/stored_requests/backends/db_fetcher/fetcher.go index 4fcebd3c6d..fc16ca490b 100644 --- a/stored_requests/backends/db_fetcher/fetcher.go +++ b/stored_requests/backends/db_fetcher/fetcher.go @@ -5,8 +5,7 @@ import ( "encoding/json" "github.com/lib/pq" - - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/stored_requests" "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" ) @@ -18,13 +17,13 @@ func NewFetcher( ) stored_requests.AllFetcher { if provider == nil { - glog.Fatalf("The Database Stored Request Fetcher requires a database connection. Please report this as a bug.") + logger.Fatalf("The Database Stored Request Fetcher requires a database connection. Please report this as a bug.") } if queryTemplate == "" { - glog.Fatalf("The Database Stored Request Fetcher requires a queryTemplate. Please report this as a bug.") + logger.Fatalf("The Database Stored Request Fetcher requires a queryTemplate. Please report this as a bug.") } if responseQueryTemplate == "" { - glog.Fatalf("The Database Stored Response Fetcher requires a responseQueryTemplate. Please report this as a bug.") + logger.Fatalf("The Database Stored Response Fetcher requires a responseQueryTemplate. Please report this as a bug.") } return &dbFetcher{ provider: provider, @@ -62,7 +61,7 @@ func (fetcher *dbFetcher) FetchRequests(ctx context.Context, requestIDs []string rows, err := fetcher.provider.QueryContext(ctx, fetcher.queryTemplate, params...) if err != nil { if err != context.DeadlineExceeded && !isBadInput(err) { - glog.Errorf("Error reading from Stored Request DB: %s", err.Error()) + logger.Errorf("Error reading from Stored Request DB: %s", err.Error()) errs := appendErrors("Request", requestIDs, nil, nil) errs = appendErrors("Imp", impIDs, nil, errs) return nil, nil, errs @@ -71,7 +70,7 @@ func (fetcher *dbFetcher) FetchRequests(ctx context.Context, requestIDs []string } defer func() { if err := rows.Close(); err != nil { - glog.Errorf("error closing DB connection: %v", err) + logger.Errorf("error closing DB connection: %v", err) } }() @@ -93,7 +92,7 @@ func (fetcher *dbFetcher) FetchRequests(ctx context.Context, requestIDs []string case "imp": storedImpData[id] = data default: - glog.Errorf("Database result set with id=%s has invalid type: %s. This will be ignored.", id, dataType) + logger.Errorf("Database result set with id=%s has invalid type: %s. This will be ignored.", id, dataType) } } @@ -127,7 +126,7 @@ func (fetcher *dbFetcher) FetchResponses(ctx context.Context, ids []string) (dat } defer func() { if err := rows.Close(); err != nil { - glog.Errorf("error closing DB connection: %v", err) + logger.Errorf("error closing DB connection: %v", err) } }() diff --git a/stored_requests/backends/db_provider/db_provider.go b/stored_requests/backends/db_provider/db_provider.go index 01cd13b7b2..be460bc351 100644 --- a/stored_requests/backends/db_provider/db_provider.go +++ b/stored_requests/backends/db_provider/db_provider.go @@ -4,8 +4,8 @@ import ( "context" "database/sql" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" ) type DbProvider interface { @@ -31,15 +31,15 @@ func NewDbProvider(dataType config.DataType, cfg config.DatabaseConnection) DbPr cfg: cfg, } default: - glog.Fatalf("Unsupported database driver %s", cfg.Driver) + logger.Fatalf("Unsupported database driver %s", cfg.Driver) return nil } if err := provider.Open(); err != nil { - glog.Fatalf("Failed to open %s database connection: %v", dataType, err) + logger.Fatalf("Failed to open %s database connection: %v", dataType, err) } if err := provider.Ping(); err != nil { - glog.Fatalf("Failed to ping %s database: %v", dataType, err) + logger.Fatalf("Failed to ping %s database: %v", dataType, err) } return provider diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go index 5dff2fddba..c28d782e01 100644 --- a/stored_requests/backends/http_fetcher/fetcher.go +++ b/stored_requests/backends/http_fetcher/fetcher.go @@ -9,12 +9,11 @@ import ( "net/url" "strings" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/stored_requests" "github.com/prebid/prebid-server/v3/util/jsonutil" - jsonpatch "gopkg.in/evanphx/json-patch.v5" - - "github.com/golang/glog" "golang.org/x/net/context/ctxhttp" + jsonpatch "gopkg.in/evanphx/json-patch.v5" ) // NewFetcher returns a Fetcher which uses the Client to pull data from the endpoint. @@ -59,9 +58,9 @@ func NewFetcher(client *http.Client, endpoint string, useRfcCompliantBuilder boo endpointURL, err := url.Parse(endpoint) if err != nil { - glog.Fatalf(`Invalid endpoint "%s": %v`, endpoint, err) + logger.Fatalf(`Invalid endpoint "%s": %v`, endpoint, err) } - glog.Infof("Making http_fetcher for endpoint %v", endpoint) + logger.Infof("Making http_fetcher for endpoint %v", endpoint) return &HttpFetcher{ client: client, diff --git a/stored_requests/caches/memory/cache.go b/stored_requests/caches/memory/cache.go index c7c9f7ceea..bae7a7ddcf 100644 --- a/stored_requests/caches/memory/cache.go +++ b/stored_requests/caches/memory/cache.go @@ -6,7 +6,7 @@ import ( "sync" "github.com/coocood/freecache" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/stored_requests" ) @@ -19,10 +19,10 @@ import ( func NewCache(size int, ttl int, dataType string) stored_requests.CacheJSON { if ttl > 0 && size <= 0 { // a positive ttl indicates "LRU" cache type, while unlimited size indicates an "unbounded" cache type - glog.Fatalf("unbounded in-memory %s cache with TTL not allowed. Config validation should have caught this. Failing fast because something is buggy.", dataType) + logger.Fatalf("unbounded in-memory %s cache with TTL not allowed. Config validation should have caught this. Failing fast because something is buggy.", dataType) } if size > 0 { - glog.Infof("Using a Stored %s in-memory cache. Max size: %d bytes. TTL: %d seconds.", dataType, size, ttl) + logger.Infof("Using a Stored %s in-memory cache. Max size: %d bytes. TTL: %d seconds.", dataType, size, ttl) return &cache{ dataType: dataType, cache: &pbsLRUCache{ @@ -31,7 +31,7 @@ func NewCache(size int, ttl int, dataType string) stored_requests.CacheJSON { }, } } else { - glog.Infof("Using an unbounded Stored %s in-memory cache.", dataType) + logger.Infof("Using an unbounded Stored %s in-memory cache.", dataType) return &cache{ dataType: dataType, cache: &pbsSyncMap{&sync.Map{}}, diff --git a/stored_requests/caches/memory/maps.go b/stored_requests/caches/memory/maps.go index 9678c4b90e..adf5b2a90d 100644 --- a/stored_requests/caches/memory/maps.go +++ b/stored_requests/caches/memory/maps.go @@ -5,7 +5,7 @@ import ( "sync" "github.com/coocood/freecache" - "github.com/golang/glog" + "github.com/prebid/prebid-server/v3/logger" ) // This file contains an interface and some wrapper types for various types of "map-like" structures @@ -52,14 +52,14 @@ func (m *pbsLRUCache) Get(id string) (json.RawMessage, bool) { return val, true } if err != freecache.ErrNotFound { - glog.Errorf("unexpected error from freecache: %v", err) + logger.Errorf("unexpected error from freecache: %v", err) } return val, false } func (m *pbsLRUCache) Set(id string, value json.RawMessage) { if err := m.Cache.Set([]byte(id), value, m.ttlSeconds); err != nil { - glog.Errorf("error saving value in freecache: %v", err) + logger.Errorf("error saving value in freecache: %v", err) } } diff --git a/stored_requests/config/config.go b/stored_requests/config/config.go index fd82e87842..5ff729cdd3 100644 --- a/stored_requests/config/config.go +++ b/stored_requests/config/config.go @@ -5,11 +5,10 @@ import ( "net/http" "time" - "github.com/prebid/prebid-server/v3/metrics" - - "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/stored_requests" "github.com/prebid/prebid-server/v3/stored_requests/backends/db_fetcher" "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" @@ -39,7 +38,7 @@ func CreateStoredRequests(cfg *config.StoredRequests, metricsEngine metrics.Metr // Create database connection if given options for one if cfg.Database.ConnectionInfo.Database != "" { if provider == nil { - glog.Infof("Connecting to Database for Stored %s. Driver=%s, DB=%s, host=%s, port=%d, user=%s", + logger.Infof("Connecting to Database for Stored %s. Driver=%s, DB=%s, host=%s, port=%d, user=%s", cfg.DataType(), cfg.Database.ConnectionInfo.Driver, cfg.Database.ConnectionInfo.Database, @@ -51,7 +50,7 @@ func CreateStoredRequests(cfg *config.StoredRequests, metricsEngine metrics.Metr // Error out if config is trying to use multiple database connections for different stored requests (not supported yet) if provider.Config() != cfg.Database.ConnectionInfo { - glog.Fatal("Multiple database connection settings found in config, only a single database connection is currently supported.") + logger.Fatalf("Multiple database connection settings found in config, only a single database connection is currently supported.") } } @@ -76,7 +75,7 @@ func CreateStoredRequests(cfg *config.StoredRequests, metricsEngine metrics.Metr } if err := provider.Close(); err != nil { - glog.Errorf("Error closing DB connection: %v", err) + logger.Errorf("Error closing DB connection: %v", err) } } @@ -157,7 +156,7 @@ func newFetcher(cfg *config.StoredRequests, client *http.Client, provider db_pro idList = append(idList, fFetcher) } if cfg.Database.FetcherQueries.QueryTemplate != "" { - glog.Infof("Loading Stored %s data via Database.\nQuery: %s", cfg.DataType(), cfg.Database.FetcherQueries.QueryTemplate) + logger.Infof("Loading Stored %s data via Database.\nQuery: %s", cfg.DataType(), cfg.Database.FetcherQueries.QueryTemplate) idList = append(idList, db_fetcher.NewFetcher(provider, cfg.Database.FetcherQueries.QueryTemplate, cfg.Database.FetcherQueries.QueryTemplate)) } else if cfg.Database.CacheInitialization.Query != "" && cfg.Database.PollUpdates.Query != "" { @@ -165,7 +164,7 @@ func newFetcher(cfg *config.StoredRequests, client *http.Client, provider db_pro idList = append(idList, empty_fetcher.EmptyFetcher{}) } if cfg.HTTP.Endpoint != "" { - glog.Infof("Loading Stored %s data via HTTP. endpoint=%s", cfg.DataType(), cfg.HTTP.Endpoint) + logger.Infof("Loading Stored %s data via HTTP. endpoint=%s", cfg.DataType(), cfg.HTTP.Endpoint) idList = append(idList, http_fetcher.NewFetcher(client, cfg.HTTP.Endpoint, cfg.HTTP.UseRfcCompliantBuilder)) } @@ -182,7 +181,7 @@ func newCache(cfg *config.StoredRequests) stored_requests.Cache { } switch { case cfg.InMemoryCache.Type == "none": - glog.Warningf("No %s cache configured. The %s Fetcher backend will be used for all data requests", cfg.DataType(), cfg.DataType()) + logger.Warnf("No %s cache configured. The %s Fetcher backend will be used for all data requests", cfg.DataType(), cfg.DataType()) case cfg.DataType() == config.AccountDataType: cache.Accounts = memory.NewCache(cfg.InMemoryCache.Size, cfg.InMemoryCache.TTL, "Accounts") default: @@ -234,10 +233,10 @@ func newHttpEvents(client *http.Client, timeout time.Duration, refreshRate time. } func newFilesystem(dataType config.DataType, configPath string) stored_requests.AllFetcher { - glog.Infof("Loading Stored %s data from filesystem at path %s", dataType, configPath) + logger.Infof("Loading Stored %s data from filesystem at path %s", dataType, configPath) fetcher, err := file_fetcher.NewFileFetcher(configPath) if err != nil { - glog.Fatalf("Failed to create a %s FileFetcher: %v", dataType, err) + logger.Fatalf("Failed to create a %s FileFetcher: %v", dataType, err) } return fetcher } @@ -247,9 +246,9 @@ func consolidate(dataType config.DataType, fetchers []stored_requests.AllFetcher if len(fetchers) == 0 { switch dataType { case config.RequestDataType: - glog.Warning("No Stored Request support configured. request.imp[i].ext.prebid.storedrequest will be ignored. If you need this, check your app config") + logger.Warnf("No Stored Request support configured. request.imp[i].ext.prebid.storedrequest will be ignored. If you need this, check your app config") default: - glog.Warningf("No Stored %s support configured. If you need this, check your app config", dataType) + logger.Warnf("No Stored %s support configured. If you need this, check your app config", dataType) } return empty_fetcher.EmptyFetcher{} } else if len(fetchers) == 1 { diff --git a/stored_requests/events/database/database.go b/stored_requests/events/database/database.go index 965922b270..1ab768c97c 100644 --- a/stored_requests/events/database/database.go +++ b/stored_requests/events/database/database.go @@ -8,8 +8,8 @@ import ( "net" "time" - "github.com/golang/glog" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/metrics" "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" "github.com/prebid/prebid-server/v3/stored_requests/events" @@ -49,7 +49,7 @@ type DatabaseEventProducer struct { func NewDatabaseEventProducer(cfg DatabaseEventProducerConfig) (eventProducer *DatabaseEventProducer) { if cfg.Provider == nil { - glog.Fatalf("The Database Stored %s Loader needs a database connection to work.", cfg.RequestType) + logger.Fatalf("The Database Stored %s Loader needs a database connection to work.", cfg.RequestType) } return &DatabaseEventProducer{ @@ -88,7 +88,7 @@ func (e *DatabaseEventProducer) fetchAll() (fetchErr error) { e.recordFetchTime(elapsedTime, metrics.FetchAll) if err != nil { - glog.Warningf("Failed to fetch all Stored %s data from the DB: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to fetch all Stored %s data from the DB: %v", e.cfg.RequestType, err) if _, ok := err.(net.Error); ok { e.recordError(metrics.StoredDataErrorNetwork) } else { @@ -99,13 +99,13 @@ func (e *DatabaseEventProducer) fetchAll() (fetchErr error) { defer func() { if err := rows.Close(); err != nil { - glog.Warningf("Failed to close the Stored %s DB connection: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to close the Stored %s DB connection: %v", e.cfg.RequestType, err) e.recordError(metrics.StoredDataErrorUndefined) fetchErr = err } }() if err := e.sendEvents(rows); err != nil { - glog.Warningf("Failed to load all Stored %s data from the DB: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to load all Stored %s data from the DB: %v", e.cfg.RequestType, err) e.recordError(metrics.StoredDataErrorUndefined) return err } @@ -130,7 +130,7 @@ func (e *DatabaseEventProducer) fetchDelta() (fetchErr error) { e.recordFetchTime(elapsedTime, metrics.FetchDelta) if err != nil { - glog.Warningf("Failed to fetch updated Stored %s data from the DB: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to fetch updated Stored %s data from the DB: %v", e.cfg.RequestType, err) if _, ok := err.(net.Error); ok { e.recordError(metrics.StoredDataErrorNetwork) } else { @@ -141,13 +141,13 @@ func (e *DatabaseEventProducer) fetchDelta() (fetchErr error) { defer func() { if err := rows.Close(); err != nil { - glog.Warningf("Failed to close the Stored %s DB connection: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to close the Stored %s DB connection: %v", e.cfg.RequestType, err) e.recordError(metrics.StoredDataErrorUndefined) fetchErr = err } }() if err := e.sendEvents(rows); err != nil { - glog.Warningf("Failed to load updated Stored %s data from the DB: %v", e.cfg.RequestType, err) + logger.Warnf("Failed to load updated Stored %s data from the DB: %v", e.cfg.RequestType, err) e.recordError(metrics.StoredDataErrorUndefined) return err } @@ -213,7 +213,7 @@ func (e *DatabaseEventProducer) sendEvents(rows *sql.Rows) (err error) { storedRespData[id] = data } default: - glog.Warningf("Stored Data with id=%s has invalid type: %s. This will be ignored.", id, dataType) + logger.Warnf("Stored Data with id=%s has invalid type: %s. This will be ignored.", id, dataType) } } diff --git a/stored_requests/events/http/http.go b/stored_requests/events/http/http.go index ec17bd0773..f987afb658 100644 --- a/stored_requests/events/http/http.go +++ b/stored_requests/events/http/http.go @@ -9,13 +9,11 @@ import ( "net/url" "time" - "golang.org/x/net/context/ctxhttp" - "github.com/buger/jsonparser" + "github.com/prebid/prebid-server/v3/logger" "github.com/prebid/prebid-server/v3/stored_requests/events" "github.com/prebid/prebid-server/v3/util/jsonutil" - - "github.com/golang/glog" + "golang.org/x/net/context/ctxhttp" ) // NewHTTPEvents makes an EventProducer which creates events by pinging an external HTTP API @@ -77,7 +75,7 @@ func NewHTTPEvents(client *httpCore.Client, endpoint string, ctxProducer func() saves: make(chan events.Save, 1), invalidations: make(chan events.Invalidation, 1), } - glog.Infof("Loading HTTP cache from GET %s", endpoint) + logger.Infof("Loading HTTP cache from GET %s", endpoint) e.fetchAll() go e.refresh(time.Tick(refreshRate)) @@ -118,7 +116,7 @@ func (e *HTTPEvents) refresh(ticker <-chan time.Time) { // Error with url parsing if urlErr != nil { - glog.Errorf("Disabling refresh HTTP cache from GET '%s': %v", e.Endpoint, urlErr) + logger.Errorf("Disabling refresh HTTP cache from GET '%s': %v", e.Endpoint, urlErr) return } @@ -134,7 +132,7 @@ func (e *HTTPEvents) refresh(ticker <-chan time.Time) { // Convert to string endpoint := endpointUrl.String() - glog.Infof("Refreshing HTTP cache from GET '%s'", endpoint) + logger.Infof("Refreshing HTTP cache from GET '%s'", endpoint) ctx, cancel := e.ctxProducer() resp, err := ctxhttp.Get(ctx, e.client, endpoint) @@ -166,25 +164,25 @@ func (e *HTTPEvents) refresh(ticker <-chan time.Time) { // It returns true if everything was successful, and false if any errors occurred. func (e *HTTPEvents) parse(endpoint string, resp *httpCore.Response, err error) (*responseContract, bool) { if err != nil { - glog.Errorf("Failed call: GET %s for Stored Requests: %v", endpoint, err) + logger.Errorf("Failed call: GET %s for Stored Requests: %v", endpoint, err) return nil, false } defer resp.Body.Close() respBytes, err := io.ReadAll(resp.Body) if err != nil { - glog.Errorf("Failed to read body of GET %s for Stored Requests: %v", endpoint, err) + logger.Errorf("Failed to read body of GET %s for Stored Requests: %v", endpoint, err) return nil, false } if resp.StatusCode != httpCore.StatusOK { - glog.Errorf("Got %d response from GET %s for Stored Requests. Response body was: %s", resp.StatusCode, endpoint, string(respBytes)) + logger.Errorf("Got %d response from GET %s for Stored Requests. Response body was: %s", resp.StatusCode, endpoint, string(respBytes)) return nil, false } var respObj responseContract if err := jsonutil.UnmarshalValid(respBytes, &respObj); err != nil { - glog.Errorf("Failed to unmarshal body of GET %s for Stored Requests: %v", endpoint, err) + logger.Errorf("Failed to unmarshal body of GET %s for Stored Requests: %v", endpoint, err) return nil, false } From d08d278084b78180f1376e9f7e537cadfed5e571 Mon Sep 17 00:00:00 2001 From: "Adserver.Online" <61009237+adserver-online@users.noreply.github.com> Date: Sat, 10 Jan 2026 02:27:13 +0200 Subject: [PATCH 136/272] Aso: Add user sync endpoint to adapter and aliases (#4580) --- static/bidder-info/aso.yaml | 8 +++----- static/bidder-info/bcmint.yaml | 8 +++----- static/bidder-info/bidgency.yaml | 8 +++----- static/bidder-info/kuantyx.yaml | 8 +++----- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/static/bidder-info/aso.yaml b/static/bidder-info/aso.yaml index 429b8441a5..6d0a86d490 100644 --- a/static/bidder-info/aso.yaml +++ b/static/bidder-info/aso.yaml @@ -14,8 +14,6 @@ capabilities: - video - native userSync: - # Adserver.Online supports user syncing, but requires configuration by the host.Contact this - # bidder directly at the email address in this file to ask about enabling user sync. - supports: - - redirect - - iframe + redirect: + url: "https://track.aso1.net/sync/v2?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "{uid}" diff --git a/static/bidder-info/bcmint.yaml b/static/bidder-info/bcmint.yaml index 9d5a62cc51..8e42dcb986 100644 --- a/static/bidder-info/bcmint.yaml +++ b/static/bidder-info/bcmint.yaml @@ -3,8 +3,6 @@ endpoint: "https://srv.datacygnal.io/pbs/bidder?zid={{.ZoneID}}" maintainer: email: "contact@bcm.ltd" userSync: - # BCM Int. supports user syncing, but requires configuration by the host.Contact this - # bidder directly at the email address in this file to ask about enabling user sync. - supports: - - redirect - - iframe \ No newline at end of file + redirect: + url: "https://track.datacygnal.io/sync/v2?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "{uid}" diff --git a/static/bidder-info/bidgency.yaml b/static/bidder-info/bidgency.yaml index ad5816dffe..e4885897d1 100644 --- a/static/bidder-info/bidgency.yaml +++ b/static/bidder-info/bidgency.yaml @@ -3,8 +3,6 @@ endpoint: "https://srv.bidgx.com/pbs/bidder?zid={{.ZoneID}}" maintainer: email: "aso@bidgency.com" userSync: - # Bidgency supports user syncing, but requires configuration by the host.Contact this - # bidder directly at the email address in this file to ask about enabling user sync. - supports: - - redirect - - iframe \ No newline at end of file + redirect: + url: "https://track.bidgx.com/sync/v2?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "{uid}" diff --git a/static/bidder-info/kuantyx.yaml b/static/bidder-info/kuantyx.yaml index b4a2402450..6b92e8c4e7 100644 --- a/static/bidder-info/kuantyx.yaml +++ b/static/bidder-info/kuantyx.yaml @@ -3,8 +3,6 @@ endpoint: "https://srv.kntxy.com/pbs/bidder?zid={{.ZoneID}}" maintainer: email: "ssp@kuantyx.com" userSync: - # Kuantyx supports user syncing, but requires configuration by the host.Contact this - # bidder directly at the email address in this file to ask about enabling user sync. - supports: - - redirect - - iframe + redirect: + url: "https://track.kntxy.com/sync/v2?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "{uid}" From 4df02847d51b739f9f1be23e424102e8e972d8f3 Mon Sep 17 00:00:00 2001 From: khouajaSadok <mohamedsadok.khouaja@we-are-adot.com> Date: Sat, 10 Jan 2026 20:55:08 +0100 Subject: [PATCH 137/272] Adot: Constrain publisher path to an enum list (#4573) --- adapters/adot/params_test.go | 2 +- static/bidder-params/adot.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/adapters/adot/params_test.go b/adapters/adot/params_test.go index 99f8c9d932..a64401e14a 100644 --- a/adapters/adot/params_test.go +++ b/adapters/adot/params_test.go @@ -44,7 +44,6 @@ var validParams = []string{ `{"placementId": "test-113", "parallax": true}`, `{"placementId": "test-113", "parallax": false}`, `{"placementId": "test-113", "parallax": false, "publisherPath": "/hubvisor"}`, - `{"placementId": "test-113", "parallax": false, "publisherPath": ""}`, } var invalidParams = []string{ @@ -55,4 +54,5 @@ var invalidParams = []string{ `{"placementId": 142, "parallax": true}`, `{"placementId": "test-114", "parallax": 1}`, `{"placementId": "test-114", "parallax": true, "publisherPath": 111}`, + `{"placementId": "test-113", "parallax": false, "publisherPath": ""}`, } diff --git a/static/bidder-params/adot.json b/static/bidder-params/adot.json index e82b17be8d..45caca4da8 100644 --- a/static/bidder-params/adot.json +++ b/static/bidder-params/adot.json @@ -14,7 +14,8 @@ }, "publisherPath": { "type": "string", - "description": "An optional path used in the bid endpoint" + "enum": ["/hubvisor", "/spotx"], + "description": "An optional path used in the bid endpoint. Only '/hubvisor' and '/spotx' are allowed." } }, "required": [] From 83ce1cd576dc524fe0944ac2eb713ac6fcee3177 Mon Sep 17 00:00:00 2001 From: patryk-grzegorczyk <131142828+patryk-grzegorczyk@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:10:31 +0100 Subject: [PATCH 138/272] AdOcean: Remove adapter (#4296) --- adapters/adocean/adocean.go | 408 ------------------ adapters/adocean/adocean_test.go | 28 -- .../exemplary/multi-banner-impression.json | 135 ------ .../exemplary/single-banner-impression.json | 118 ----- .../adocean/adoceantest/supplemental/app.json | 72 ---- .../supplemental/bad-response.json | 67 --- .../supplemental/emiter-param-error.json | 55 --- .../supplemental/encode-error.json | 82 ---- .../supplemental/network-error.json | 67 --- .../adoceantest/supplemental/no-bid.json | 161 ------- .../supplemental/no-impression.json | 36 -- .../adoceantest/supplemental/no-sizes.json | 170 -------- .../supplemental/requests-merge.json | 181 -------- adapters/adocean/params_test.go | 53 --- exchange/adapter_builders.go | 2 - openrtb_ext/bidders.go | 2 - openrtb_ext/imp_adocean.go | 7 - static/bidder-info/adocean.yaml | 16 - static/bidder-params/adocean.json | 32 -- 19 files changed, 1692 deletions(-) delete mode 100644 adapters/adocean/adocean.go delete mode 100644 adapters/adocean/adocean_test.go delete mode 100644 adapters/adocean/adoceantest/exemplary/multi-banner-impression.json delete mode 100644 adapters/adocean/adoceantest/exemplary/single-banner-impression.json delete mode 100644 adapters/adocean/adoceantest/supplemental/app.json delete mode 100644 adapters/adocean/adoceantest/supplemental/bad-response.json delete mode 100644 adapters/adocean/adoceantest/supplemental/emiter-param-error.json delete mode 100644 adapters/adocean/adoceantest/supplemental/encode-error.json delete mode 100644 adapters/adocean/adoceantest/supplemental/network-error.json delete mode 100644 adapters/adocean/adoceantest/supplemental/no-bid.json delete mode 100644 adapters/adocean/adoceantest/supplemental/no-impression.json delete mode 100644 adapters/adocean/adoceantest/supplemental/no-sizes.json delete mode 100644 adapters/adocean/adoceantest/supplemental/requests-merge.json delete mode 100644 adapters/adocean/params_test.go delete mode 100644 openrtb_ext/imp_adocean.go delete mode 100644 static/bidder-info/adocean.yaml delete mode 100644 static/bidder-params/adocean.json diff --git a/adapters/adocean/adocean.go b/adapters/adocean/adocean.go deleted file mode 100644 index 82f3200159..0000000000 --- a/adapters/adocean/adocean.go +++ /dev/null @@ -1,408 +0,0 @@ -package adocean - -import ( - "errors" - "fmt" - "math/rand" - "net/http" - "net/url" - "regexp" - "sort" - "strconv" - "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 adapterVersion = "1.3.0" -const maxUriLength = 8000 -const measurementCode = ` - <script> - +function() { - var wu = "%s"; - var su = "%s".replace(/\[TIMESTAMP\]/, Date.now()); - - if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { - (new Image(1,1)).src = wu - } - - if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { - (new Image(1,1)).src = su - } - }(); - </script> -` - -type ResponseAdUnit struct { - ID string `json:"id"` - CrID string `json:"crid"` - Currency string `json:"currency"` - Price string `json:"price"` - Width string `json:"width"` - Height string `json:"height"` - Code string `json:"code"` - WinURL string `json:"winUrl"` - StatsURL string `json:"statsUrl"` - Error string `json:"error"` -} - -type requestData struct { - Url *url.URL - Headers *http.Header - SlaveSizes map[string]string - ImpIDs []string -} - -// Builder builds a new instance of the AdOcean adapter for the given bidder with the given config. -func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) - if err != nil { - return nil, errors.New("Unable to parse endpoint template") - } - - whiteSpace := regexp.MustCompile(`\s+`) - - bidder := &AdOceanAdapter{ - endpointTemplate: endpointTemplate, - measurementCode: whiteSpace.ReplaceAllString(measurementCode, " "), - } - return bidder, nil -} - -type AdOceanAdapter struct { - endpointTemplate *template.Template - measurementCode string -} - -func (a *AdOceanAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - if len(request.Imp) == 0 { - return nil, []error{&errortypes.BadInput{ - Message: "No impression in the bid request", - }} - } - - consentString := "" - if request.User != nil { - var extUser openrtb_ext.ExtUser - if err := jsonutil.Unmarshal(request.User.Ext, &extUser); err == nil { - consentString = extUser.Consent - } - } - - var reqCreationErrors []error - var err error - requestsData := make([]*requestData, 0, len(request.Imp)) - for _, auction := range request.Imp { - requestsData, err = a.addNewBid(requestsData, &auction, request, consentString) - if err != nil { - reqCreationErrors = append(reqCreationErrors, err) - } - } - - httpRequests := make([]*adapters.RequestData, 0, len(requestsData)) - for _, requestData := range requestsData { - httpRequests = append(httpRequests, &adapters.RequestData{ - Method: "GET", - Uri: requestData.Url.String(), - Headers: *requestData.Headers, - ImpIDs: requestData.ImpIDs, - }) - } - - return httpRequests, reqCreationErrors -} - -func (a *AdOceanAdapter) addNewBid( - requestsData []*requestData, - imp *openrtb2.Imp, - request *openrtb2.BidRequest, - consentString string, -) ([]*requestData, error) { - var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - return requestsData, &errortypes.BadInput{ - Message: "Error parsing bidderExt object", - } - } - - var adOceanExt openrtb_ext.ExtImpAdOcean - if err := jsonutil.Unmarshal(bidderExt.Bidder, &adOceanExt); err != nil { - return requestsData, &errortypes.BadInput{ - Message: "Error parsing adOceanExt parameters", - } - } - - if adOceanExt.EmitterPrefix == "" { - return requestsData, &errortypes.BadInput{ - Message: "No emitterPrefix param", - } - } - - addedToExistingRequest := addToExistingRequest(requestsData, &adOceanExt, imp, (request.Test == 1)) - if addedToExistingRequest { - return requestsData, nil - } - - slaveSizes := map[string]string{} - slaveSizes[adOceanExt.SlaveID] = getImpSizes(imp) - - url, err := a.makeURL(&adOceanExt, imp, request, slaveSizes, consentString) - if err != nil { - return requestsData, err - } - - requestsData = append(requestsData, &requestData{ - Url: url, - Headers: a.formHeaders(request), - SlaveSizes: slaveSizes, - ImpIDs: []string{imp.ID}, - }) - - return requestsData, nil -} - -func addToExistingRequest(requestsData []*requestData, newParams *openrtb_ext.ExtImpAdOcean, imp *openrtb2.Imp, testImp bool) bool { - auctionID := imp.ID - - for _, requestData := range requestsData { - queryParams := requestData.Url.Query() - masterID := queryParams["id"][0] - - if masterID == newParams.MasterID { - if _, has := requestData.SlaveSizes[newParams.SlaveID]; has { - continue - } - - queryParams.Add("aid", newParams.SlaveID+":"+auctionID) - requestData.SlaveSizes[newParams.SlaveID] = getImpSizes(imp) - setSlaveSizesParam(&queryParams, requestData.SlaveSizes, testImp) - - newUrl := *(requestData.Url) - newUrl.RawQuery = queryParams.Encode() - if len(newUrl.String()) < maxUriLength { - requestData.Url = &newUrl - requestData.ImpIDs = append(requestData.ImpIDs, auctionID) - return true - } - - delete(requestData.SlaveSizes, newParams.SlaveID) - } - } - - return false -} - -func (a *AdOceanAdapter) makeURL( - params *openrtb_ext.ExtImpAdOcean, - imp *openrtb2.Imp, - request *openrtb2.BidRequest, - slaveSizes map[string]string, - consentString string, -) (*url.URL, error) { - endpointParams := macros.EndpointTemplateParams{Host: params.EmitterPrefix} - host, err := macros.ResolveMacros(a.endpointTemplate, endpointParams) - if err != nil { - return nil, &errortypes.BadInput{ - Message: "Unable to parse endpoint url template: " + err.Error(), - } - } - - endpointURL, err := url.Parse(host) - if err != nil { - return nil, &errortypes.BadInput{ - Message: "Malformed URL: " + err.Error(), - } - } - - randomizedPart := 10000000 + rand.Intn(99999999-10000000) - if request.Test == 1 { - randomizedPart = 10000000 - } - endpointURL.Path = "/_" + strconv.Itoa(randomizedPart) + "/ad.json" - - auctionID := imp.ID - queryParams := url.Values{} - queryParams.Add("pbsrv_v", adapterVersion) - queryParams.Add("id", params.MasterID) - queryParams.Add("nc", "1") - queryParams.Add("nosecure", "1") - queryParams.Add("aid", params.SlaveID+":"+auctionID) - if consentString != "" { - queryParams.Add("gdpr_consent", consentString) - queryParams.Add("gdpr", "1") - } - if request.User != nil && request.User.BuyerUID != "" { - queryParams.Add("hcuserid", request.User.BuyerUID) - } - if request.App != nil { - queryParams.Add("app", "1") - queryParams.Add("appname", request.App.Name) - queryParams.Add("appbundle", request.App.Bundle) - queryParams.Add("appdomain", request.App.Domain) - } - if request.Device != nil { - if request.Device.IFA != "" { - queryParams.Add("ifa", request.Device.IFA) - } else { - queryParams.Add("dpidmd5", request.Device.DPIDMD5) - } - - queryParams.Add("devos", request.Device.OS) - queryParams.Add("devosv", request.Device.OSV) - queryParams.Add("devmodel", request.Device.Model) - queryParams.Add("devmake", request.Device.Make) - } - - setSlaveSizesParam(&queryParams, slaveSizes, (request.Test == 1)) - endpointURL.RawQuery = queryParams.Encode() - - return endpointURL, nil -} - -func (a *AdOceanAdapter) formHeaders(req *openrtb2.BidRequest) *http.Header { - headers := make(http.Header) - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - - if req.Device != nil { - headers.Add("User-Agent", req.Device.UA) - - if req.Device.IP != "" { - headers.Add("X-Forwarded-For", req.Device.IP) - } else if req.Device.IPv6 != "" { - headers.Add("X-Forwarded-For", req.Device.IPv6) - } - } - - if req.Site != nil { - headers.Add("Referer", req.Site.Page) - } - - return &headers -} - -func getImpSizes(imp *openrtb2.Imp) string { - if imp.Banner == nil { - return "" - } - - if len(imp.Banner.Format) > 0 { - sizes := make([]string, len(imp.Banner.Format)) - for i, format := range imp.Banner.Format { - sizes[i] = strconv.FormatInt(format.W, 10) + "x" + strconv.FormatInt(format.H, 10) - } - - return strings.Join(sizes, "_") - } - - if imp.Banner.W != nil && imp.Banner.H != nil { - return strconv.FormatInt(*imp.Banner.W, 10) + "x" + strconv.FormatInt(*imp.Banner.H, 10) - } - - return "" -} - -func setSlaveSizesParam(queryParams *url.Values, slaveSizes map[string]string, orderByKey bool) { - sizeValues := make([]string, 0, len(slaveSizes)) - slaveIDs := make([]string, 0, len(slaveSizes)) - for k := range slaveSizes { - slaveIDs = append(slaveIDs, k) - } - - if orderByKey { - sort.Strings(slaveIDs) - } - - for _, slaveID := range slaveIDs { - sizes := slaveSizes[slaveID] - if sizes == "" { - continue - } - - rawSlaveID := strings.Replace(slaveID, "adocean", "", 1) - sizeValues = append(sizeValues, rawSlaveID+"~"+sizes) - } - - if len(sizeValues) > 0 { - queryParams.Set("aosspsizes", strings.Join(sizeValues, "-")) - } -} - -func (a *AdOceanAdapter) MakeBids( - internalRequest *openrtb2.BidRequest, - externalRequest *adapters.RequestData, - response *adapters.ResponseData, -) (*adapters.BidderResponse, []error) { - if response.StatusCode != http.StatusOK { - return nil, []error{fmt.Errorf("Unexpected status code: %d. Network error?", response.StatusCode)} - } - - requestURL, _ := url.Parse(externalRequest.Uri) - queryParams := requestURL.Query() - auctionIDs := queryParams["aid"] - - bidResponses := make([]ResponseAdUnit, 0) - if err := jsonutil.Unmarshal(response.Body, &bidResponses); err != nil { - return nil, []error{err} - } - - var parsedResponses = adapters.NewBidderResponseWithBidsCapacity(len(auctionIDs)) - var parsingErrors []error - var slaveToAuctionIDMap = make(map[string]string, len(auctionIDs)) - - for _, auctionFullID := range auctionIDs { - auctionIDsSlice := strings.SplitN(auctionFullID, ":", 2) - slaveToAuctionIDMap[auctionIDsSlice[0]] = auctionIDsSlice[1] - } - - for _, bid := range bidResponses { - if auctionID, found := slaveToAuctionIDMap[bid.ID]; found { - if bid.Error == "true" { - continue - } - - price, _ := strconv.ParseFloat(bid.Price, 64) - width, _ := strconv.ParseInt(bid.Width, 10, 64) - height, _ := strconv.ParseInt(bid.Height, 10, 64) - adCode, err := a.prepareAdCodeForBid(bid) - if err != nil { - parsingErrors = append(parsingErrors, err) - continue - } - - parsedResponses.Bids = append(parsedResponses.Bids, &adapters.TypedBid{ - Bid: &openrtb2.Bid{ - ID: bid.ID, - ImpID: auctionID, - Price: price, - AdM: adCode, - CrID: bid.CrID, - W: width, - H: height, - }, - BidType: openrtb_ext.BidTypeBanner, - }) - parsedResponses.Currency = bid.Currency - } - } - - return parsedResponses, parsingErrors -} - -func (a *AdOceanAdapter) prepareAdCodeForBid(bid ResponseAdUnit) (string, error) { - sspCode, err := url.QueryUnescape(bid.Code) - if err != nil { - return "", err - } - - adCode := fmt.Sprintf(a.measurementCode, bid.WinURL, bid.StatsURL) + sspCode - - return adCode, nil -} diff --git a/adapters/adocean/adocean_test.go b/adapters/adocean/adocean_test.go deleted file mode 100644 index 4fb784bfc0..0000000000 --- a/adapters/adocean/adocean_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package adocean - -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/stretchr/testify/assert" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderAdOcean, config.Adapter{ - Endpoint: "https://{{.Host}}.adocean.pl"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, "adoceantest", bidder) -} - -func TestEndpointTemplateMalformed(t *testing.T) { - _, buildErr := Builder(openrtb_ext.BidderAdOcean, config.Adapter{ - Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - assert.Error(t, buildErr) -} diff --git a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json b/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json deleted file mode 100644 index 6eac26e0d0..0000000000 --- a/adapters/adocean/adoceantest/exemplary/multi-banner-impression.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "mockBidRequest": { - "id": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b", - "source": { - "tid": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b" - }, - "tmax": 1000, - "imp": [{ - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }, { - "w": 320, - "h": 600 - }] - } - }, { - "id": "secod-twelve", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://192.168.100.203/testing/prebid_server/test.html" - }, - "device": { - "w": 418, - "h": 961, - "dpidmd5": "f2ba45ece57cff9477d5a8083b138c9g" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw" - } - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Asecod-twelve&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250_320x600&devmake=&devmodel=&devos=&devosv=&dpidmd5=f2ba45ece57cff9477d5a8083b138c9g&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test","secod-twelve"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaozpniqismex", - "price": "1", - "winurl": "https://win-url.com", - "statsUrl": "https://stats-url.com", - "code": " <!-- code 1 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }, - { - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url2.com", - "statsUrl": "https://stats-url2.com", - "code": " <!-- code 2 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - }], - "expectedBidResponses": [{ - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaozpniqismex", - "impid": "ao-test", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url.com\"; var su = \"https://stats-url.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 1 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - },{ - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "secod-twelve", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url2.com\"; var su = \"https://stats-url2.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 2 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }] -} diff --git a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json b/adapters/adocean/adoceantest/exemplary/single-banner-impression.json deleted file mode 100644 index 9f5fa2a349..0000000000 --- a/adapters/adocean/adoceantest/exemplary/single-banner-impression.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1", - "ifa": "f2ba45ece57cff9477d5a8083b138c9a" - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw" - } - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test"] - }, - "mockResponse": { - "status": 200, - "body": [ - { - "id": "adoceanmyaozpniqismex", - "price": "1", - "winurl": "https://win-url.com", - "statsUrl": "https://stats-url.com", - "code": " <!-- code 1 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }, - { - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "", - "statsUrl": "", - "code": " <!-- code 2 -->", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - } - ], - "expectedBidResponses": [ - { - "currency": "EUR", - "bids": [ - { - "bid": { - "id": "adoceanmyaozpniqismex", - "impid": "ao-test", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url.com\"; var su = \"https://stats-url.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 1 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/app.json b/adapters/adocean/adoceantest/supplemental/app.json deleted file mode 100644 index 28c67bdf81..0000000000 --- a/adapters/adocean/adoceantest/supplemental/app.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "app": { - "id": "ktdf45k34h53k5hjh5k3", - "name": "Weather App", - "cat": ["IAB15","IAB15-10"], - "ver": "1.0.2", - "bundle": "12345", - "domain": "example.com" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1", - "os": "iOS", - "devicetype": 4, - "ifa": "f2ba45ece57cff9477d5a8083b138c9a" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&app=1&appbundle=12345&appdomain=example.com&appname=Weather+App&devmake=&devmodel=&devos=iOS&devosv=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&ifa=f2ba45ece57cff9477d5a8083b138c9a&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test"] - }, - "mockResponse": { - "status": 200, - "body": "{ key: nil }" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "decode slice: expect [ or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/bad-response.json b/adapters/adocean/adoceantest/supplemental/bad-response.json deleted file mode 100644 index eb1bcb6ef0..0000000000 --- a/adapters/adocean/adoceantest/supplemental/bad-response.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test"] - }, - "mockResponse": { - "status": 200, - "body": "{ key: nil }" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "decode slice: expect [ or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/emiter-param-error.json b/adapters/adocean/adoceantest/supplemental/emiter-param-error.json deleted file mode 100644 index 154c92e851..0000000000 --- a/adapters/adocean/adoceantest/supplemental/emiter-param-error.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emiter": "myao.adocean.pl", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1" - } - }, - "expectedMakeRequestsErrors": [ - { - "value": "No emitterPrefix param", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/encode-error.json b/adapters/adocean/adoceantest/supplemental/encode-error.json deleted file mode 100644 index 32a0565da2..0000000000 --- a/adapters/adocean/adoceantest/supplemental/encode-error.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test"] - }, - "mockResponse": { - "status": 200, - "body": [ - { - "id": "adoceanmyaozpniqismex", - "price": "1", - "winurl": "", - "statsUrl": "", - "code": " <!-- code 1 --> %a", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - } - ], - "expectedBidResponses": [{"currency":"USD","bids":[]}], - "expectedMakeBidsErrors": [ - { - "value": "invalid URL escape \"%a\"", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/network-error.json b/adapters/adocean/adoceantest/supplemental/network-error.json deleted file mode 100644 index 5910a5626b..0000000000 --- a/adapters/adocean/adoceantest/supplemental/network-error.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [ - { - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - } - } - ], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aosspsizes=myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test"] - }, - "mockResponse": { - "status": 500, - "body": {} - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 500. Network error?", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/no-bid.json b/adapters/adocean/adoceantest/supplemental/no-bid.json deleted file mode 100644 index a2c9b9c7ef..0000000000 --- a/adapters/adocean/adoceantest/supplemental/no-bid.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "mockBidRequest": { - "id": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b", - "source": { - "tid": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b" - }, - "tmax": 1000, - "imp": [{ - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }, { - "id": "ao-test-two", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }, { - "id": "ao-test-three", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://localhost/prebid_server/test.html" - }, - "device": { - "w": 418, - "h": 961 - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw" - } - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test","ao-test-two"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaozpniqismex", - "error": "true" - }, - { - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url2.com", - "statsUrl": "https://stats-url2.com", - "code": " <!-- code 2 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - }, { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test-three"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url3.com", - "statsUrl": "https://stats-url3.com", - "code": " <!-- code 3 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }] - } - }], - "expectedBidResponses": [{ - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-two", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url2.com\"; var su = \"https://stats-url2.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 2 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }, { - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-three", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url3.com\"; var su = \"https://stats-url3.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 3 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }] -} diff --git a/adapters/adocean/adoceantest/supplemental/no-impression.json b/adapters/adocean/adoceantest/supplemental/no-impression.json deleted file mode 100644 index 8f2a8eef35..0000000000 --- a/adapters/adocean/adoceantest/supplemental/no-impression.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "mockBidRequest": { - "id": "9ed903f4-383d-406b-8011-4f06526cb02c", - "source": { - "tid": "9ed903f4-383d-406b-8011-4f06526cb02c" - }, - "tmax": 1000, - "imp": [], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://example.com/test.html" - }, - "device": { - "w": 1280, - "h": 720, - "ip": "192.168.1.1" - } - }, - "expectedMakeRequestsErrors": [ - { - "value": "No impression in the bid request", - "comparison": "literal" - } - ] -} diff --git a/adapters/adocean/adoceantest/supplemental/no-sizes.json b/adapters/adocean/adoceantest/supplemental/no-sizes.json deleted file mode 100644 index c469f5e095..0000000000 --- a/adapters/adocean/adoceantest/supplemental/no-sizes.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "mockBidRequest": { - "id": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b", - "source": { - "tid": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b" - }, - "tmax": 1000, - "imp": [{ - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - } - }, { - "id": "ao-test-two", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [] - } - }, { - "id": "ao-test-three", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "w": 300, - "h": 250 - } - }], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://localhost/prebid_server/test.html" - }, - "device": { - "w": 418, - "h": 961 - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw" - } - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test","ao-test-two"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaozpniqismex", - "price": "1", - "winurl": "https://win-url.com", - "statsUrl": "https://stats-url.com", - "code": " <!-- code 1 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }, - { - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url2.com", - "statsUrl": "https://stats-url2.com", - "code": " <!-- code 2 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - }, { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test-three"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url3.com", - "statsUrl": "https://stats-url3.com", - "code": " <!-- code 3 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }] - } - }], - "expectedBidResponses": [{ - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaozpniqismex", - "impid": "ao-test", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url.com\"; var su = \"https://stats-url.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 1 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }, { - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-two", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url2.com\"; var su = \"https://stats-url2.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 2 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }, { - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-three", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url3.com\"; var su = \"https://stats-url3.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 3 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }] -} diff --git a/adapters/adocean/adoceantest/supplemental/requests-merge.json b/adapters/adocean/adoceantest/supplemental/requests-merge.json deleted file mode 100644 index 240c74bc77..0000000000 --- a/adapters/adocean/adoceantest/supplemental/requests-merge.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "mockBidRequest": { - "id": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b", - "source": { - "tid": "b5300274-a7ec-4cdb-bf5b-d75eeb481a6b" - }, - "tmax": 1000, - "imp": [{ - "id": "ao-test", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaozpniqismex" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }, { - "id": "ao-test-two", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }, { - "id": "ao-test-three", - "ext": { - "bidder": { - "emitterPrefix": "myao", - "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", - "slaveId": "adoceanmyaowafpdwlrks" - } - }, - "banner": { - "format": [{ - "w": 300, - "h": 250 - }] - } - }], - "test": 1, - "ext": { - "prebid": { - "targeting": { - "includewinners": true, - "includebidderkeys": false - } - } - }, - "site": { - "publisher": { - "id": "1" - }, - "page": "http://localhost/prebid_server/test.html" - }, - "device": { - "w": 418, - "h": 961 - }, - "regs": { - "ext": { - "gdpr": 1 - } - }, - "user": { - "ext": { - "consent": "COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw" - } - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaozpniqismex%3Aao-test&aid=adoceanmyaowafpdwlrks%3Aao-test-two&aosspsizes=myaowafpdwlrks~300x250-myaozpniqismex~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test","ao-test-two"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaozpniqismex", - "price": "1", - "winurl": "https://win-url.com", - "statsUrl": "https://stats-url.com", - "code": " <!-- code 1 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }, - { - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url2.com", - "statsUrl": "https://stats-url2.com", - "code": " <!-- code 2 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - } - ] - } - }, { - "expectedRequest": { - "uri": "https://myao.adocean.pl/_10000000/ad.json?aid=adoceanmyaowafpdwlrks%3Aao-test-three&aosspsizes=myaowafpdwlrks~300x250&devmake=&devmodel=&devos=&devosv=&dpidmd5=&gdpr=1&gdpr_consent=COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1&pbsrv_v=1.3.0", - "impIDs":["ao-test-three"] - }, - "mockResponse": { - "status": 200, - "body": [{ - "id": "adoceanmyaowafpdwlrks", - "price": "1", - "winurl": "https://win-url3.com", - "statsUrl": "https://stats-url3.com", - "code": " <!-- code 3 --> ", - "currency": "EUR", - "minFloorPrice": "0.01", - "width": "300", - "height": "250", - "crid": "0af345b42983cc4bc0", - "ttl": "300" - }] - } - }], - "expectedBidResponses": [{ - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaozpniqismex", - "impid": "ao-test", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url.com\"; var su = \"https://stats-url.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 1 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }, { - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-two", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url2.com\"; var su = \"https://stats-url2.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 2 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }, { - "currency": "EUR", - "bids": [{ - "bid": { - "id": "adoceanmyaowafpdwlrks", - "impid": "ao-test-three", - "price": 1, - "adm": " <script> +function() { var wu = \"https://win-url3.com\"; var su = \"https://stats-url3.com\".replace(/\\[TIMESTAMP\\]/, Date.now()); if (wu && !(navigator.sendBeacon && navigator.sendBeacon(wu))) { (new Image(1,1)).src = wu } if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); </script> <!-- code 3 --> ", - "crid": "0af345b42983cc4bc0", - "w": 300, - "h": 250 - }, - "type": "banner" - }] - }] -} diff --git a/adapters/adocean/params_test.go b/adapters/adocean/params_test.go deleted file mode 100644 index 0840d10847..0000000000 --- a/adapters/adocean/params_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package adocean - -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.BidderAdOcean, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected adocean 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.BidderAdOcean, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } - } -} - -var validParams = []string{ - `{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emiter": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, -} - -var invalidParams = []string{ - `{}`, - `{"emitterPrefix": "myao", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"}`, - `{"emitterPrefix": "", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emitterPrefix": "myao", "", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": ""}`, - `{"emitterPrefix": "myao", "masterId": "tmYF.DMl7Z utQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emitterPrefix": "myao", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmy iqismex"}`, - `{"emitterPrefix": "myao.adocean.pl", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emiter": "myao.adocean.pl", "slaveId": "adoceanmyaozpniqismex"}`, - `{"emiter": "", "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7", "slaveId": "adoceanmyaozpniqismex"}`, -} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e6bba140a5..c4b333257f 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -17,7 +17,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/admatic" "github.com/prebid/prebid-server/v3/adapters/admixer" "github.com/prebid/prebid-server/v3/adapters/adnuntius" - "github.com/prebid/prebid-server/v3/adapters/adocean" "github.com/prebid/prebid-server/v3/adapters/adoppler" "github.com/prebid/prebid-server/v3/adapters/adot" "github.com/prebid/prebid-server/v3/adapters/adpone" @@ -287,7 +286,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdmatic: admatic.Builder, openrtb_ext.BidderAdmixer: admixer.Builder, openrtb_ext.BidderAdnuntius: adnuntius.Builder, - openrtb_ext.BidderAdOcean: adocean.Builder, openrtb_ext.BidderAdoppler: adoppler.Builder, openrtb_ext.BidderAdot: adot.Builder, openrtb_ext.BidderAdpone: adpone.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 82a6df4f77..c5a71834b4 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -33,7 +33,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdmatic, BidderAdmixer, BidderAdnuntius, - BidderAdOcean, BidderAdoppler, BidderAdot, BidderAdpone, @@ -410,7 +409,6 @@ const ( BidderAdmatic BidderName = "admatic" BidderAdmixer BidderName = "admixer" BidderAdnuntius BidderName = "adnuntius" - BidderAdOcean BidderName = "adocean" BidderAdoppler BidderName = "adoppler" BidderAdot BidderName = "adot" BidderAdpone BidderName = "adpone" diff --git a/openrtb_ext/imp_adocean.go b/openrtb_ext/imp_adocean.go deleted file mode 100644 index 1dd64d284e..0000000000 --- a/openrtb_ext/imp_adocean.go +++ /dev/null @@ -1,7 +0,0 @@ -package openrtb_ext - -type ExtImpAdOcean struct { - EmitterPrefix string `json:"emitterPrefix"` - MasterID string `json:"masterId"` - SlaveID string `json:"slaveId"` -} diff --git a/static/bidder-info/adocean.yaml b/static/bidder-info/adocean.yaml deleted file mode 100644 index 3932a7a75e..0000000000 --- a/static/bidder-info/adocean.yaml +++ /dev/null @@ -1,16 +0,0 @@ -endpoint: "https://{{.Host}}.adocean.pl" -maintainer: - email: "aoteam@gemius.com" -gvlVendorID: 328 -capabilities: - app: - mediaTypes: - - banner - site: - mediaTypes: - - banner -userSync: - # adocean supports user syncing, but requires configuration by the host. contact this - # bidder directly at the email address in this file to ask about enabling user sync. - supports: - - redirect diff --git a/static/bidder-params/adocean.json b/static/bidder-params/adocean.json deleted file mode 100644 index a3c5cbc95d..0000000000 --- a/static/bidder-params/adocean.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "AdOcean Adapter Params", - "description": "A schema which validates params accepted by the AdOcean adapter", - "type": "object", - "properties": { - "emiter": { - "type": "string", - "description": "Deprecated, use emitterPrefix instead. AdOcean emiter", - "pattern": ".+" - }, - "emitterPrefix": { - "type": "string", - "description": "AdOcean emitter prefix", - "pattern": "^[\\w\\-]+$" - }, - "masterId": { - "type": "string", - "description": "Master's id", - "pattern": "^[\\w.]+$" - }, - "slaveId": { - "type": "string", - "description": "Slave's id", - "pattern": "^adocean[\\w.]+$" - } - }, - "oneOf": [ - { "required": ["emiter", "masterId", "slaveId"] }, - { "required": ["emitterPrefix", "masterId", "slaveId"] } - ] -} From 1f3371fe1ea9096a3068f188a4c1191aa7cbe416 Mon Sep 17 00:00:00 2001 From: ProgrammaticX <pxteam@programmaticx.ai> Date: Sat, 10 Jan 2026 22:34:01 +0200 Subject: [PATCH 139/272] ProgX: Change alias of (#4352) --- static/bidder-info/progx.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/static/bidder-info/progx.yaml b/static/bidder-info/progx.yaml index 0e203e8e46..45a27ecfa6 100644 --- a/static/bidder-info/progx.yaml +++ b/static/bidder-info/progx.yaml @@ -1,9 +1,12 @@ -aliasOf: "vidazoo" -endpoint: "https://exchange.programmaticx.ai/openrtb/" +aliasOf: 'teqblaze' +endpoint: "https://us-east.progrtb.com/pserver" maintainer: email: "pxteam@programmaticx.ai" gvlVendorID: 1344 userSync: + redirect: + url: "https://sync.progrtb.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" iframe: - url: https://sync.programmaticx.ai/api/user/html/685297194d85991a5e6e36dd?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} - userMacro: ${userId} \ No newline at end of file + url: "https://sync.progrtb.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 9428862202ed9a3ee5e7a5ab71be99c570727a2d Mon Sep 17 00:00:00 2001 From: AdsInteractive <marton.vargha@adsinteractive.hu> Date: Sat, 10 Jan 2026 22:44:09 +0200 Subject: [PATCH 140/272] AdsInteractive: Change to aliases (#4359) --- adapters/ads_interactive/ads_interactive.go | 158 ----------- .../ads_interactive/ads_interactive_test.go | 20 -- .../exemplary/endpointId.json | 136 ---------- .../exemplary/multi-format.json | 105 -------- .../exemplary/multi-imp.json | 253 ------------------ .../exemplary/simple-banner.json | 136 ---------- .../exemplary/simple-native.json | 120 --------- .../exemplary/simple-video.json | 131 --------- .../exemplary/simple-web-banner.json | 136 ---------- .../supplemental/bad_media_type.json | 83 ------ .../supplemental/bad_response.json | 85 ------ .../supplemental/no-valid-bidder-param.json | 42 --- .../supplemental/no-valid-imp-ext.json | 38 --- .../supplemental/status-204.json | 80 ------ .../supplemental/status-not-200.json | 85 ------ adapters/ads_interactive/params_test.go | 52 ---- adapters/adsinteractive/adsinteractive.go | 80 ------ .../adsinteractive/adsinteractive_test.go | 23 -- .../adsinteractivetest/exemplary/banner.json | 90 ------- .../supplemental/bad-request-400.json | 65 ----- .../supplemental/bad-response.json | 64 ----- .../supplemental/no-content-204.json | 57 ---- .../supplemental/service-unavailable-503.json | 64 ----- adapters/adsinteractive/params_test.go | 55 ---- exchange/adapter_builders.go | 4 - openrtb_ext/bidders.go | 4 - openrtb_ext/imp_ads_interactive.go | 6 - openrtb_ext/imp_adsinteractive.go | 5 - static/bidder-info/ads_interactive.yaml | 12 +- static/bidder-info/adsinteractive.yaml | 23 +- static/bidder-params/ads_interactive.json | 22 -- static/bidder-params/adsinteractive.json | 13 - 32 files changed, 10 insertions(+), 2237 deletions(-) delete mode 100644 adapters/ads_interactive/ads_interactive.go delete mode 100644 adapters/ads_interactive/ads_interactive_test.go delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/endpointId.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/multi-format.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/multi-imp.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/simple-banner.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/simple-native.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/simple-video.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/exemplary/simple-web-banner.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/bad_media_type.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/bad_response.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-bidder-param.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-imp-ext.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/status-204.json delete mode 100644 adapters/ads_interactive/ads_interactivetest/supplemental/status-not-200.json delete mode 100644 adapters/ads_interactive/params_test.go delete mode 100644 adapters/adsinteractive/adsinteractive.go delete mode 100644 adapters/adsinteractive/adsinteractive_test.go delete mode 100644 adapters/adsinteractive/adsinteractivetest/exemplary/banner.json delete mode 100644 adapters/adsinteractive/adsinteractivetest/supplemental/bad-request-400.json delete mode 100644 adapters/adsinteractive/adsinteractivetest/supplemental/bad-response.json delete mode 100644 adapters/adsinteractive/adsinteractivetest/supplemental/no-content-204.json delete mode 100644 adapters/adsinteractive/adsinteractivetest/supplemental/service-unavailable-503.json delete mode 100644 adapters/adsinteractive/params_test.go delete mode 100644 openrtb_ext/imp_ads_interactive.go delete mode 100644 openrtb_ext/imp_adsinteractive.go delete mode 100644 static/bidder-params/ads_interactive.json delete mode 100644 static/bidder-params/adsinteractive.json diff --git a/adapters/ads_interactive/ads_interactive.go b/adapters/ads_interactive/ads_interactive.go deleted file mode 100644 index 5b46ec5248..0000000000 --- a/adapters/ads_interactive/ads_interactive.go +++ /dev/null @@ -1,158 +0,0 @@ -package ads_interactive - -import ( - "encoding/json" - "fmt" - "net/http" - - "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/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" -) - -type adapter struct { - endpoint string -} - -type reqBodyExt struct { - AdsInteractiveBidderExt reqBodyExtBidder `json:"bidder"` -} - -type reqBodyExtBidder struct { - Type string `json:"type"` - PlacementID string `json:"placementId,omitempty"` - EndpointID string `json:"endpointId,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) { - var errs []error - var adapterRequests []*adapters.RequestData - - for _, imp := range request.Imp { - reqCopy := *request - reqCopy.Imp = []openrtb2.Imp{imp} - - var bidderExt adapters.ExtImpBidder - var adsInteractiveExt openrtb_ext.ImpExtAdsInteractive - - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - errs = append(errs, err) - continue - } - if err := jsonutil.Unmarshal(bidderExt.Bidder, &adsInteractiveExt); err != nil { - errs = append(errs, err) - continue - } - - impExt := reqBodyExt{AdsInteractiveBidderExt: reqBodyExtBidder{}} - - if adsInteractiveExt.PlacementID != "" { - impExt.AdsInteractiveBidderExt.PlacementID = adsInteractiveExt.PlacementID - impExt.AdsInteractiveBidderExt.Type = "publisher" - } else if adsInteractiveExt.EndpointID != "" { - impExt.AdsInteractiveBidderExt.EndpointID = adsInteractiveExt.EndpointID - impExt.AdsInteractiveBidderExt.Type = "network" - } - - finalImpExt, err := json.Marshal(impExt) - if err != nil { - errs = append(errs, err) - continue - } - - reqCopy.Imp[0].Ext = finalImpExt - - adapterReq, err := a.makeRequest(&reqCopy) - if err != nil { - errs = append(errs, err) - continue - } - - if adapterReq != nil { - adapterRequests = append(adapterRequests, adapterReq) - } - } - - if len(adapterRequests) == 0 { - return nil, errs - } - - return adapterRequests, nil -} - -func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) { - reqJSON, err := json.Marshal(request) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - return &adapters.RequestData{ - Method: "POST", - Uri: a.endpoint, - Body: reqJSON, - Headers: headers, - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - }, nil -} - -func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if adapters.IsResponseStatusCodeNoContent(responseData) { - return nil, nil - } - - if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { - return nil, []error{err} - } - - var response openrtb2.BidResponse - if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { - return nil, []error{err} - } - - bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) - if len(response.Cur) != 0 { - bidResponse.Currency = response.Cur - } - - for _, seatBid := range response.SeatBid { - for i := range seatBid.Bid { - bidType, err := getBidType(seatBid.Bid[i]) - if err != nil { - return nil, []error{err} - } - - b := &adapters.TypedBid{ - Bid: &seatBid.Bid[i], - BidType: bidType, - } - bidResponse.Bids = append(bidResponse.Bids, b) - } - } - return bidResponse, nil -} - -func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { - // determinate media type by bid response field mtype - 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 - } - - return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) -} diff --git a/adapters/ads_interactive/ads_interactive_test.go b/adapters/ads_interactive/ads_interactive_test.go deleted file mode 100644 index f8a16d50a1..0000000000 --- a/adapters/ads_interactive/ads_interactive_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package ads_interactive - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderAdsInteractive, config.Adapter{ - Endpoint: "https://example.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, "ads_interactivetest", bidder) -} diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/endpointId.json b/adapters/ads_interactive/ads_interactivetest/exemplary/endpointId.json deleted file mode 100644 index 14aa475656..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/endpointId.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test", - "type": "network" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/multi-format.json b/adapters/ads_interactive/ads_interactivetest/exemplary/multi-format.json deleted file mode 100644 index 9e897a9a1b..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/multi-format.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "video": { - "mimes": [ - "video/mp4" - ], - "protocols": [ - 2, - 5 - ], - "w": 1024, - "h": 576 - }, - "ext": { - "bidder": { - "endpointId": "test" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "video": { - "mimes": [ - "video/mp4" - ], - "protocols": [ - 2, - 5 - ], - "w": 1024, - "h": 576 - }, - "ext": { - "bidder": { - "endpointId": "test", - "type": "network" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 204 - } - } - ], - "expectedBidResponses": [] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/multi-imp.json b/adapters/ads_interactive/ads_interactivetest/exemplary/multi-imp.json deleted file mode 100644 index dbba92907d..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/multi-imp.json +++ /dev/null @@ -1,253 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test" - } - } - }, - { - "id": "test-imp-id2", - "tagid": "test2", - "banner": { - "format": [ - { - "w": 3000, - "h": 2500 - }, - { - "w": 3000, - "h": 6000 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test2" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test", - "type": "network" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - }, - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id2", - "tagid": "test2", - "banner": { - "format": [ - { - "w": 3000, - "h": 2500 - }, - { - "w": 3000, - "h": 6000 - } - ] - }, - "ext": { - "bidder": { - "endpointId": "test2", - "type": "network" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id2"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id2", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 3000, - "h": 2500, - "ext": { - "prebid": { - "type": "banner" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - }, - "type": "banner" - } - ] - }, - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id2", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 3000, - "h": 2500, - "ext": { - "prebid": { - "type": "banner" - } - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-banner.json b/adapters/ads_interactive/ads_interactivetest/exemplary/simple-banner.json deleted file mode 100644 index f28f425623..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-banner.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-native.json b/adapters/ads_interactive/ads_interactivetest/exemplary/simple-native.json deleted file mode 100644 index b46c8a3961..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-native.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "native": { - "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", - "ver": "1.1" - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "native": { - "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", - "ver": "1.1" - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 4, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "native" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 4, - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "native" - } - } - }, - "type": "native" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-video.json b/adapters/ads_interactive/ads_interactivetest/exemplary/simple-video.json deleted file mode 100644 index 8d6475b7b9..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-video.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "video": { - "mimes": [ - "video/mp4" - ], - "protocols": [ - 2, - 5 - ], - "w": 1024, - "h": 576 - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "video": { - "mimes": [ - "video/mp4" - ], - "protocols": [ - 2, - 5 - ], - "w": 1024, - "h": 576 - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ] - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 2, - "ext": { - "prebid": { - "type": "video" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 2, - "ext": { - "prebid": { - "type": "video" - } - } - }, - "type": "video" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-web-banner.json b/adapters/ads_interactive/ads_interactivetest/exemplary/simple-web-banner.json deleted file mode 100644 index 4f973035ed..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/exemplary/simple-web-banner.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ], - "site": { - "id": "1", - "domain": "test.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Ubuntu" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "site": { - "id": "1", - "domain": "test.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Ubuntu" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 468, - "h": 60, - "ext": { - "prebid": { - "type": "banner" - } - } - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "mtype": 1, - "w": 468, - "h": 60, - "ext": { - "prebid": { - "type": "banner" - } - } - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/bad_media_type.json b/adapters/ads_interactive/ads_interactivetest/supplemental/bad_media_type.json deleted file mode 100644 index ca500d19a5..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/bad_media_type.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://example.com&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "w": 300, - "h": 250, - "ext": {} - } - ], - "seat": "ads_interactive" - } - ], - "cur": "USD" - } - } - }], - "expectedMakeBidsErrors": [ - { - "value": "could not define media type for impression: test-imp-id", - "comparison": "literal" - } - ] -} diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/bad_response.json b/adapters/ads_interactive/ads_interactivetest/supplemental/bad_response.json deleted file mode 100644 index 476058ed62..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/bad_response.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": "" - } - }], - "expectedMakeBidsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-bidder-param.json b/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-bidder-param.json deleted file mode 100644 index fe0631c032..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-bidder-param.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "endpointId": [] - } - } - } - ] - }, - "expectedMakeRequestsErrors": [ - { - "value": "cannot unmarshal openrtb_ext.ImpExtAdsInteractive.EndpointID: expects \" or n, but found [", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-imp-ext.json b/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-imp-ext.json deleted file mode 100644 index 09108b2d84..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/no-valid-imp-ext.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "iPad" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": "invalid" - } - ] - }, - "expectedMakeRequestsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/status-204.json b/adapters/ads_interactive/ads_interactivetest/supplemental/status-204.json deleted file mode 100644 index 7dd1c65fd3..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/status-204.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - }], - "expectedBidResponses": [] -} diff --git a/adapters/ads_interactive/ads_interactivetest/supplemental/status-not-200.json b/adapters/ads_interactive/ads_interactivetest/supplemental/status-not-200.json deleted file mode 100644 index 743f299626..0000000000 --- a/adapters/ads_interactive/ads_interactivetest/supplemental/status-not-200.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "https://example.com", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "ext": { - "bidder": { - "placementId": "test", - "type": "publisher" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 404, - "body": {} - } - }], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} diff --git a/adapters/ads_interactive/params_test.go b/adapters/ads_interactive/params_test.go deleted file mode 100644 index ec7dc6302e..0000000000 --- a/adapters/ads_interactive/params_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package ads_interactive - -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 schema. %v", err) - } - - for _, p := range validParams { - if err := validator.Validate(openrtb_ext.BidderAdsInteractive, json.RawMessage(p)); err != nil { - t.Errorf("Schema rejected valid params: %s", p) - } - } -} - -func TestInvalidParams(t *testing.T) { - validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") - if err != nil { - t.Fatalf("Failed to fetch the json schema. %v", err) - } - - for _, p := range invalidParams { - if err := validator.Validate(openrtb_ext.BidderAdsInteractive, json.RawMessage(p)); err == nil { - t.Errorf("Schema allowed invalid params: %s", p) - } - } -} - -var validParams = []string{ - `{"placementId": "test"}`, - `{"placementId": "1"}`, - `{"endpointId": "test"}`, - `{"endpointId": "1"}`, - `{"placementId": "test", "unknownField": "value"}`, -} - -var invalidParams = []string{ - `{}`, - `{"placementId": 42}`, - `{"endpointId": 42}`, - `{"placementId": "1", "endpointId": "1"}`, - `{"placementId": ""}`, - `{"endpointId": ""}`, - `{"randomField": "value"}`, -} diff --git a/adapters/adsinteractive/adsinteractive.go b/adapters/adsinteractive/adsinteractive.go deleted file mode 100644 index 1969ceb7cc..0000000000 --- a/adapters/adsinteractive/adsinteractive.go +++ /dev/null @@ -1,80 +0,0 @@ -package adsinteractive - -import ( - "encoding/json" - "fmt" - "net/http" - - "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" -) - -type adapter struct { - endpoint string -} - -// Builder builds a new instance of the Adsinteractive adapter for the given bidder with the given config. -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, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - requestJSON, err := json.Marshal(request) - if err != nil { - return nil, []error{err} - } - - requestData := &adapters.RequestData{ - Method: "POST", - Uri: a.endpoint, - Body: requestJSON, - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - } - - return []*adapters.RequestData{requestData}, nil -} - -func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if responseData.StatusCode == http.StatusNoContent { - return nil, nil - } - - if responseData.StatusCode == http.StatusBadRequest { - err := &errortypes.BadInput{ - Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", - } - return nil, []error{err} - } - - if responseData.StatusCode != http.StatusOK { - err := &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), - } - return nil, []error{err} - } - - var response openrtb2.BidResponse - if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { - return nil, []error{err} - } - - bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) - bidResponse.Currency = response.Cur - for _, seatBid := range response.SeatBid { - for i := range seatBid.Bid { - b := &adapters.TypedBid{ - Bid: &seatBid.Bid[i], - BidType: "banner", - } - bidResponse.Bids = append(bidResponse.Bids, b) - } - } - return bidResponse, nil -} diff --git a/adapters/adsinteractive/adsinteractive_test.go b/adapters/adsinteractive/adsinteractive_test.go deleted file mode 100644 index ae83c615fe..0000000000 --- a/adapters/adsinteractive/adsinteractive_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package adsinteractive - -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" -) - -const testsDir = "adsinteractivetest" -const testsBidderEndpoint = "http://bid.adsinteractive.com/prebid" - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderAdsinteractive, config.Adapter{ - Endpoint: testsBidderEndpoint}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, testsDir, bidder) -} diff --git a/adapters/adsinteractive/adsinteractivetest/exemplary/banner.json b/adapters/adsinteractive/adsinteractivetest/exemplary/banner.json deleted file mode 100644 index bc4d4c7091..0000000000 --- a/adapters/adsinteractive/adsinteractivetest/exemplary/banner.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "site": { - "page": "https://good.site/url" - }, - "imp": [ - { - "id": "test-imp-id", - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://bid.adsinteractive.com/prebid", - "body": { - "id": "test-request-id", - "site": { - "page": "https://good.site/url" - }, - "imp": [ - { - "id": "test-imp-id", - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "adsinteractive", - "bid": [ - { - "id": "randomid", - "impid": "test-imp-id", - "price": 0.72, - "adid": "12345678", - "adm": "some-test-ad", - "cid": "987", - "crid": "12345678", - "h": 250, - "w": 300 - } - ] - } - ], - "cur": "EUR" - } - } - } - ], - - "expectedBidResponses": [ - { - "currency": "EUR", - "bids": [ - { - "bid": { - "id": "randomid", - "impid": "test-imp-id", - "price": 0.72, - "adm": "some-test-ad", - "adid": "12345678", - "cid": "987", - "crid": "12345678", - "w": 300, - "h": 250 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/adsinteractive/adsinteractivetest/supplemental/bad-request-400.json b/adapters/adsinteractive/adsinteractivetest/supplemental/bad-request-400.json deleted file mode 100644 index d584c81144..0000000000 --- a/adapters/adsinteractive/adsinteractivetest/supplemental/bad-request-400.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - - "httpCalls": [ - { - - "expectedRequest": { - "uri": "http://bid.adsinteractive.com/prebid", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 400, - "body": {} - } - } - ], - - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", - "comparison": "literal" - } - ] -} diff --git a/adapters/adsinteractive/adsinteractivetest/supplemental/bad-response.json b/adapters/adsinteractive/adsinteractivetest/supplemental/bad-response.json deleted file mode 100644 index 3f40cfa351..0000000000 --- a/adapters/adsinteractive/adsinteractivetest/supplemental/bad-response.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://bid.adsinteractive.com/prebid", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": "" - } - } - ], - - "expectedMakeBidsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/adsinteractive/adsinteractivetest/supplemental/no-content-204.json b/adapters/adsinteractive/adsinteractivetest/supplemental/no-content-204.json deleted file mode 100644 index ee5adb9193..0000000000 --- a/adapters/adsinteractive/adsinteractivetest/supplemental/no-content-204.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "fake-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - } - } - } - ] - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://bid.adsinteractive.com/prebid", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "fake-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - } - } - } - ] - }, - "impIDs":["fake-imp-id"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - } - ], - - "expectedBidResponses": [] -} diff --git a/adapters/adsinteractive/adsinteractivetest/supplemental/service-unavailable-503.json b/adapters/adsinteractive/adsinteractivetest/supplemental/service-unavailable-503.json deleted file mode 100644 index 2800076417..0000000000 --- a/adapters/adsinteractive/adsinteractivetest/supplemental/service-unavailable-503.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://bid.adsinteractive.com/prebid", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": { - "adUnit": "fake-adunit-name" - } - } - } - ] - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 503, - "body": {} - } - } - ], - - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 503. Run with request.debug = 1 for more info.", - "comparison": "literal" - } - ] -} diff --git a/adapters/adsinteractive/params_test.go b/adapters/adsinteractive/params_test.go deleted file mode 100644 index 6b377d6aa3..0000000000 --- a/adapters/adsinteractive/params_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package adsinteractive - -import ( - "encoding/json" - "testing" - - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -// This file actually intends to test static/bidder-params/adsinteractive.json - -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.BidderAdsinteractive, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected adsinteractive params: %s", validParam) - } - } -} - -// TestInvalidParams makes sure that the Adsinteractive schema rejects all the imp.ext fields we don't support. -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.BidderAdsinteractive, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } - } -} - -var validParams = []string{ - `{"adUnit": "Example_ad_unit_1"}`, -} - -var invalidParams = []string{ - `{"adunit": "Example_ad_unit_1"}`, - `{"AdUnit": "Example_ad_unit_1"}`, - `{"ad_unit": Example_ad_unit_1}`, - ``, - `null`, - `true`, - `[]`, - `{}`, - `nil`, - `53`, - `9.1`, -} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index c4b333257f..3cb651bcbd 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -23,8 +23,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/adprime" "github.com/prebid/prebid-server/v3/adapters/adquery" "github.com/prebid/prebid-server/v3/adapters/adrino" - "github.com/prebid/prebid-server/v3/adapters/ads_interactive" - "github.com/prebid/prebid-server/v3/adapters/adsinteractive" "github.com/prebid/prebid-server/v3/adapters/adtarget" "github.com/prebid/prebid-server/v3/adapters/adtelligent" "github.com/prebid/prebid-server/v3/adapters/adtonos" @@ -292,8 +290,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdprime: adprime.Builder, openrtb_ext.BidderAdquery: adquery.Builder, openrtb_ext.BidderAdrino: adrino.Builder, - openrtb_ext.BidderAdsInteractive: ads_interactive.Builder, - openrtb_ext.BidderAdsinteractive: adsinteractive.Builder, openrtb_ext.BidderAdtarget: adtarget.Builder, openrtb_ext.BidderAdtrgtme: adtrgtme.Builder, openrtb_ext.BidderAdtelligent: adtelligent.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index c5a71834b4..e94d0fe551 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -39,8 +39,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdprime, BidderAdquery, BidderAdrino, - BidderAdsInteractive, - BidderAdsinteractive, BidderAdtarget, BidderAdtrgtme, BidderAdtelligent, @@ -415,8 +413,6 @@ const ( BidderAdprime BidderName = "adprime" BidderAdquery BidderName = "adquery" BidderAdrino BidderName = "adrino" - BidderAdsInteractive BidderName = "ads_interactive" - BidderAdsinteractive BidderName = "adsinteractive" BidderAdtarget BidderName = "adtarget" BidderAdtrgtme BidderName = "adtrgtme" BidderAdTonos BidderName = "adtonos" diff --git a/openrtb_ext/imp_ads_interactive.go b/openrtb_ext/imp_ads_interactive.go deleted file mode 100644 index f7a02e2dd2..0000000000 --- a/openrtb_ext/imp_ads_interactive.go +++ /dev/null @@ -1,6 +0,0 @@ -package openrtb_ext - -type ImpExtAdsInteractive struct { - PlacementID string `json:"placementId"` - EndpointID string `json:"endpointId"` -} diff --git a/openrtb_ext/imp_adsinteractive.go b/openrtb_ext/imp_adsinteractive.go deleted file mode 100644 index c382b2d6e5..0000000000 --- a/openrtb_ext/imp_adsinteractive.go +++ /dev/null @@ -1,5 +0,0 @@ -package openrtb_ext - -type ImpExtAdsinteractive struct { - AdUnit string `json:"adUnit"` -} diff --git a/static/bidder-info/ads_interactive.yaml b/static/bidder-info/ads_interactive.yaml index dd857366b5..df45a6869e 100644 --- a/static/bidder-info/ads_interactive.yaml +++ b/static/bidder-info/ads_interactive.yaml @@ -1,18 +1,8 @@ +aliasOf: "teqblaze" endpoint: "https://bntb.adsinteractive.com/pserver" gvlVendorID: 1212 maintainer: email: "it@adsinteractive.com" -capabilities: - site: - mediaTypes: - - banner - - video - - native - app: - mediaTypes: - - banner - - video - - native userSync: redirect: url: "https://cstb.adsinteractive.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" diff --git a/static/bidder-info/adsinteractive.yaml b/static/bidder-info/adsinteractive.yaml index 095184725b..0940039929 100644 --- a/static/bidder-info/adsinteractive.yaml +++ b/static/bidder-info/adsinteractive.yaml @@ -1,17 +1,12 @@ -endpoint: "http://bid.adsinteractive.com/prebid" -maintainer: - email: it@adsinteractive.com +aliasOf: "teqblaze" +endpoint: "https://bntb.adsinteractive.com/pserver" gvlVendorID: 1212 -modifyingVastXmlAllowed: false -capabilities: - app: - mediaTypes: - - banner - site: - mediaTypes: - - banner +maintainer: + email: "it@adsinteractive.com" userSync: redirect: - url: "https://sync.adsinteractive.com/getuid?{{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}" - userMacro: "$AUID" - + url: "https://cstb.adsinteractive.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://cstb.adsinteractive.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file diff --git a/static/bidder-params/ads_interactive.json b/static/bidder-params/ads_interactive.json deleted file mode 100644 index 6a750b9c18..0000000000 --- a/static/bidder-params/ads_interactive.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Ads Interactive Adapter Params", - "description": "A schema which validates params accepted by the Ads Interactive adapter", - "type": "object", - "properties": { - "placementId": { - "type": "string", - "minLength": 1, - "description": "Placement ID" - }, - "endpointId": { - "type": "string", - "minLength": 1, - "description": "Endpoint ID" - } - }, - "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } - ] -} \ No newline at end of file diff --git a/static/bidder-params/adsinteractive.json b/static/bidder-params/adsinteractive.json deleted file mode 100644 index 662c7362ba..0000000000 --- a/static/bidder-params/adsinteractive.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Adsinteractive Adapter Params", - "description": "Adsinteractive Bidder Parameter Schema", - "type": "object", - "properties": { - "adUnit": { - "type": "string", - "description": "ad unit name" - } - }, - "required": ["adUnit"] -} From bd6bbfb22060330206f9d8cae1b12e64bd39bce8 Mon Sep 17 00:00:00 2001 From: Valentino <57947465+Valentino3@users.noreply.github.com> Date: Sat, 10 Jan 2026 18:05:17 -0300 Subject: [PATCH 141/272] ResetDigital: Switch to OpenRTB (#4475) --- adapters/resetdigital/params_test.go | 8 +- adapters/resetdigital/resetdigital.go | 414 ++++------ adapters/resetdigital/resetdigital_test.go | 734 +++++++++++++++++- .../exemplary/simple-audio.json | 182 ++--- .../exemplary/simple-banner.json | 197 ++--- .../exemplary/simple-video.json | 120 --- .../supplemental/bad-ext-bidder.json | 30 + .../supplemental/bad-ext-resetdigital.json | 32 + .../supplemental/bad-response-body.json | 74 ++ .../supplemental/currency-fallback.json | 105 +++ .../supplemental/empty-response.json | 80 ++ .../supplemental/imp-id-mismatch.json | 91 --- .../supplemental/invalid-bid-height.json | 91 --- .../supplemental/invalid-bid-width.json | 91 --- .../supplemental/invalid-cur.json | 75 -- .../supplemental/invalid-device.json | 73 -- .../supplemental/invalid-media-def.json | 35 - .../supplemental/invalid-placement-id.json | 43 - .../supplemental/invalid-video-dim.json | 76 -- .../supplemental/malformed-response.json | 78 -- .../supplemental/missing-currency.json | 98 --- .../supplemental/mtype-audio.json | 95 +++ .../supplemental/mtype-banner.json | 107 +++ .../supplemental/mtype-native.json | 93 +++ .../supplemental/mtype-video.json | 103 +++ .../supplemental/multi-format.json | 107 --- .../supplemental/multiple-bids.json | 103 --- .../supplemental/multiple-imp-error.json | 49 ++ .../supplemental/native-mediatype.json | 91 +++ .../supplemental/no-matching-impression.json | 97 +++ .../supplemental/status-400.json | 72 ++ .../supplemental/status-500.json | 72 ++ .../supplemental/unknown-media.json | 67 -- .../supplemental/zero-price-bid.json | 111 +++ .../resetdigitaltest/video/simple-video.json | 122 +++ static/bidder-info/resetdigital.yaml | 26 +- static/bidder-params/resetdigital.json | 22 +- 37 files changed, 2430 insertions(+), 1634 deletions(-) delete mode 100644 adapters/resetdigital/resetdigitaltest/exemplary/simple-video.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-bidder.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-resetdigital.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/bad-response-body.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/currency-fallback.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/empty-response.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/imp-id-mismatch.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-height.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-width.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-cur.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-device.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-media-def.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-placement-id.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/invalid-video-dim.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/malformed-response.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/missing-currency.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/mtype-audio.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/mtype-banner.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/mtype-native.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/mtype-video.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/multi-format.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/multiple-bids.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/multiple-imp-error.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/native-mediatype.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/no-matching-impression.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/status-400.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/status-500.json delete mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/unknown-media.json create mode 100644 adapters/resetdigital/resetdigitaltest/supplemental/zero-price-bid.json create mode 100644 adapters/resetdigital/resetdigitaltest/video/simple-video.json diff --git a/adapters/resetdigital/params_test.go b/adapters/resetdigital/params_test.go index 4098b44493..5b8c776d9d 100644 --- a/adapters/resetdigital/params_test.go +++ b/adapters/resetdigital/params_test.go @@ -7,7 +7,6 @@ import ( "github.com/prebid/prebid-server/v3/openrtb_ext" ) -// TestValidParams tests valid parameter(s) declared in openrtb_ext/imp_resetdigital.go func TestValidParams(t *testing.T) { validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") if err != nil { @@ -21,7 +20,6 @@ func TestValidParams(t *testing.T) { } } -// TestValidParams tests invalid parameter(s) declared in openrtb_ext/imp_resetdigital.go func TestInvalidParams(t *testing.T) { validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") if err != nil { @@ -35,17 +33,13 @@ func TestInvalidParams(t *testing.T) { } } -// list of valid parameter(s) test cases var validParams = []string{ `{"placement_id":"1000"}`, `{"placement_id":"0"}`, `{"placement_id":"abc"}`, `{"placement_id":"123abc"}`, - `{}`, - `{"cp":"1000"}`, } -// list of invalid parameter(s) test cases var invalidParams = []string{ ``, `null`, @@ -55,4 +49,6 @@ var invalidParams = []string{ `[]`, `{"placement_id":}`, `{"placement_id":""}`, + `{"placement_id": 123}`, + `{"cp":"1000"}`, } diff --git a/adapters/resetdigital/resetdigital.go b/adapters/resetdigital/resetdigital.go index 2a619e7604..54b5f38daa 100644 --- a/adapters/resetdigital/resetdigital.go +++ b/adapters/resetdigital/resetdigital.go @@ -4,305 +4,231 @@ import ( "encoding/json" "fmt" "net/http" - "strconv" - "text/template" + "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" + "golang.org/x/text/currency" ) -type adapter struct { - endpoint *template.Template - endpointUri string -} - -type resetDigitalRequest struct { - Site resetDigitalSite `json:"site"` - Imps []resetDigitalImp `json:"imps"` -} -type resetDigitalSite struct { - Domain string `json:"domain"` - Referrer string `json:"referrer"` -} -type resetDigitalImp struct { - ZoneID resetDigitalImpZone `json:"zone_id"` - BidID string `json:"bid_id"` - ImpID string `json:"imp_id"` - Ext resetDigitalImpExt `json:"ext"` - MediaTypes resetDigitalMediaTypes `json:"media_types"` -} -type resetDigitalImpZone struct { - PlacementID string `json:"placementId"` -} -type resetDigitalImpExt struct { - Gpid string `json:"gpid"` -} -type resetDigitalMediaTypes struct { - Banner resetDigitalMediaType `json:"banner,omitempty"` - Video resetDigitalMediaType `json:"video,omitempty"` - Audio resetDigitalMediaType `json:"audio,omitempty"` -} -type resetDigitalMediaType struct { - Sizes [][]int64 `json:"sizes,omitempty"` - Mimes []string `json:"mimes,omitempty"` -} -type resetDigitalBidResponse struct { - Bids []resetDigitalBid `json:"bids"` -} -type resetDigitalBid struct { - BidID string `json:"bid_id"` - ImpID string `json:"imp_id"` - CPM float64 `json:"cpm"` - CID string `json:"cid,omitempty"` - CrID string `json:"crid,omitempty"` - AdID string `json:"adid"` - W string `json:"w,omitempty"` - H string `json:"h,omitempty"` - Seat string `json:"seat"` - HTML string `json:"html"` -} +const ( + contentTypeJSON = "application/json" + openRTBVersion = "2.6" + currencyUSD = "USD" + bidderSeat = "resetdigital" +) -func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - template, 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: template, - } - return bidder, nil +var baseHeaders = http.Header{ + "Content-Type": []string{contentTypeJSON}, + "Accept": []string{contentTypeJSON}, + "X-OpenRTB-Version": []string{openRTBVersion}, } -func getHeaders(request *openrtb2.BidRequest) http.Header { - headers := http.Header{} - - addNonEmptyHeaders(&headers, map[string]string{ - "Content-Type": "application/json;charset=utf-8", - "Accept": "application/json", - }) - - if request != nil && request.Device != nil { - addNonEmptyHeaders(&headers, map[string]string{ - "Accept-Language": request.Device.Language, - "User-Agent": request.Device.UA, - "X-Forwarded-For": request.Device.IP, - "X-Real-Ip": request.Device.IP, - }) - } - if request != nil && request.Site != nil { - addNonEmptyHeaders(&headers, map[string]string{ - "Referer": request.Site.Page, - }) - } - - return headers +type adapter struct { + endpoint string } -func addNonEmptyHeaders(headers *http.Header, headerValues map[string]string) { - for key, value := range headerValues { - if len(value) > 0 { - headers.Add(key, value) - } - } +func Builder(_ openrtb_ext.BidderName, cfg config.Adapter, _ config.Server) (adapters.Bidder, error) { + return &adapter{ + endpoint: cfg.Endpoint, + }, nil } -func (a *adapter) MakeRequests(requestData *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - var ( - requests []*adapters.RequestData - errors []error - ) - - for _, imp := range requestData.Imp { - bidType, err := getBidType(imp) - if err != nil { - errors = append(errors, err) - continue - } - - splittedRequestData, err := processDataFromRequest(requestData, imp, bidType) - if err != nil { - errors = append(errors, err) - continue - } - - requestBody, err := json.Marshal(splittedRequestData) - - if err != nil { - errors = append(errors, err) - continue - } +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - requests = append(requests, &adapters.RequestData{ - Method: "POST", - Uri: a.endpointUri, - Body: requestBody, - Headers: getHeaders(requestData), - ImpIDs: []string{imp.ID}, - }) + if len(request.Imp) != 1 { + return nil, []error{&errortypes.BadInput{ + Message: "ResetDigital adapter supports only one impression per request", + }} } - return requests, errors -} - -func processDataFromRequest(requestData *openrtb2.BidRequest, imp openrtb2.Imp, bidType openrtb_ext.BidType) (resetDigitalRequest, error) { - var reqData resetDigitalRequest - - if requestData.Site != nil { - reqData.Site.Domain = requestData.Site.Domain - reqData.Site.Referrer = requestData.Site.Page + imp := request.Imp[0] + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Error parsing bidderExt from imp.ext: %v", err), + }} } - rdImp := resetDigitalImp{ - BidID: requestData.ID, - ImpID: imp.ID, + var resetDigitalExt openrtb_ext.ImpExtResetDigital + if err := json.Unmarshal(bidderExt.Bidder, &resetDigitalExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Error parsing resetDigitalExt from bidderExt.bidder: %v", err), + }} + } + + reqCopy := openrtb2.BidRequest{ + ID: request.ID, + Source: request.Source, + TMax: request.TMax, + Test: request.Test, + Imp: []openrtb2.Imp{imp}, + Device: request.Device, + Site: request.Site, + App: request.App, + User: request.User, + Regs: request.Regs, + Ext: request.Ext, + AT: request.AT, + BAdv: request.BAdv, + BCat: request.BCat, + BSeat: request.BSeat, + WLang: request.WLang, + WSeat: request.WSeat, + } + + if imp.TagID == "" { + reqCopy.Imp[0].TagID = resetDigitalExt.PlacementID + } + + reqCopy.Cur = validateAndFilterCurrencies(request.Cur) + + reqBody, err := json.Marshal(&reqCopy) + if err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Error marshalling OpenRTB request: %v", err), + }} } - if bidType == openrtb_ext.BidTypeBanner && imp.Banner != nil { - var tempH, tempW int64 - if imp.Banner.H != nil { - tempH = *imp.Banner.H - } - if imp.Banner.W != nil { - tempW = *imp.Banner.W - } - if tempH > 0 && tempW > 0 { - rdImp.MediaTypes.Banner.Sizes = append(rdImp.MediaTypes.Banner.Sizes, []int64{tempW, tempH}) - } - } - if bidType == openrtb_ext.BidTypeVideo && imp.Video != nil { - var tempH, tempW int64 - if imp.Video.H != nil { - tempH = *imp.Video.H - } - if imp.Video.W != nil { - tempW = *imp.Video.W - } - if tempH > 0 && tempW > 0 { - rdImp.MediaTypes.Video.Sizes = append(rdImp.MediaTypes.Video.Sizes, []int64{tempW, tempH}) - } - if imp.Video.MIMEs != nil { - rdImp.MediaTypes.Video.Mimes = append(rdImp.MediaTypes.Video.Mimes, imp.Video.MIMEs...) - } - } - if bidType == openrtb_ext.BidTypeAudio && imp.Audio != nil && imp.Audio.MIMEs != nil { - rdImp.MediaTypes.Audio.Mimes = append(rdImp.MediaTypes.Audio.Mimes, imp.Audio.MIMEs...) - } + uri := fmt.Sprintf("%s?pid=%s", a.endpoint, resetDigitalExt.PlacementID) - var bidderExt adapters.ExtImpBidder - var resetDigitalExt openrtb_ext.ImpExtResetDigital + reqHeaders := baseHeaders.Clone() - if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { - return resetDigitalRequest{}, err - } - if err := json.Unmarshal(bidderExt.Bidder, &resetDigitalExt); err != nil { - return resetDigitalRequest{}, err + reqs := []*adapters.RequestData{ + { + Method: http.MethodPost, + Uri: uri, + Body: reqBody, + Headers: reqHeaders, + ImpIDs: []string{imp.ID}, + }, } - rdImp.ZoneID.PlacementID = resetDigitalExt.PlacementID - - reqData.Imps = append(reqData.Imps, rdImp) - return reqData, nil + return reqs, nil } -func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if adapters.IsResponseStatusCodeNoContent(responseData) { +func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if responseData.StatusCode == http.StatusNoContent { return nil, nil } - if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { - return nil, []error{err} + if responseData.StatusCode >= http.StatusBadRequest && responseData.StatusCode < http.StatusInternalServerError { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", responseData.StatusCode), + }} } - var response resetDigitalBidResponse - if err := json.Unmarshal(responseData.Body, &response); err != nil { - return nil, []error{err} + if responseData.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", responseData.StatusCode), + }} } - if len(response.Bids) != 1 { - return nil, []error{fmt.Errorf("expected exactly one bid in the response, but got %d", len(response.Bids))} + var bidResp openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Bad server response: %s", err), + }} } - resetDigitalBid := &response.Bids[0] - - requestImp, found := findRequestImpByID(request.Imp, resetDigitalBid.ImpID) - if !found { - return nil, []error{fmt.Errorf("no matching impression found for ImpID %s", resetDigitalBid.ImpID)} + if len(bidResp.SeatBid) == 0 { + return nil, nil } - bid, err := getBidFromResponse(resetDigitalBid) - if err != nil { - return nil, []error{err} + return parseBidResponse(request, &bidResp) +} + +func parseBidResponse(request *openrtb2.BidRequest, bidResp *openrtb2.BidResponse) (*adapters.BidderResponse, []error) { + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid)) + var errs []error + + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } else { + cur := validateAndFilterCurrencies(request.Cur) + bidResponse.Currency = cur[0] } - bidType := GetMediaTypeForImp(requestImp) + for _, seatBid := range bidResp.SeatBid { + for i := range seatBid.Bid { + if seatBid.Bid[i].Price <= 0 { + errs = append(errs, &errortypes.Warning{ + Message: fmt.Sprintf("price %f <= 0 filtered out", seatBid.Bid[i].Price), + }) + continue + } - bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) - bidResponse.Currency = "USD" // Default currency - bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ - Bid: bid, - BidType: bidType, - Seat: openrtb_ext.BidderName(resetDigitalBid.Seat), - }) + bidType, err := getBidType(seatBid.Bid[i], request) + if err != nil { + errs = append(errs, err) + continue + } - return bidResponse, nil -} + seat := openrtb_ext.BidderName(bidderSeat) + if seatBid.Seat != "" { + seat = openrtb_ext.BidderName(seatBid.Seat) + } -// findRequestImpByID searches for an impression by its ID in the list of impressions -func findRequestImpByID(imps []openrtb2.Imp, impID string) (openrtb2.Imp, bool) { - for _, imp := range imps { - if imp.ID == impID { - return imp, true + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + Seat: seat, + }) } } - return openrtb2.Imp{}, false -} - -func getBidFromResponse(bidResponse *resetDigitalBid) (*openrtb2.Bid, error) { - bid := &openrtb2.Bid{ - ID: bidResponse.BidID, - Price: bidResponse.CPM, - ImpID: bidResponse.ImpID, - CID: bidResponse.CID, - CrID: bidResponse.CrID, - AdM: bidResponse.HTML, - } + return bidResponse, errs +} - w, err := strconv.ParseInt(bidResponse.W, 10, 64) - if err != nil { - return nil, err +func getBidType(bid openrtb2.Bid, request *openrtb2.BidRequest) (openrtb_ext.BidType, error) { + if bid.MType > 0 { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + } } - bid.W = w - - h, err := strconv.ParseInt(bidResponse.H, 10, 64) - if err != nil { - return nil, err + if request.Imp[0].ID != bid.ImpID { + return "", fmt.Errorf("no matching impression found for ImpID: %s", bid.ImpID) } - bid.H = h - return bid, nil + return getMediaType(request.Imp[0]), nil } -func getBidType(imp openrtb2.Imp) (openrtb_ext.BidType, error) { - if imp.Banner != nil { - return openrtb_ext.BidTypeBanner, nil - } else if imp.Video != nil { - return openrtb_ext.BidTypeVideo, nil - } else if imp.Audio != nil { - return openrtb_ext.BidTypeAudio, nil +func validateAndFilterCurrencies(currencies []string) []string { + valid := make([]string, 0, len(currencies)) + for _, s := range currencies { + s = strings.TrimSpace(s) + if s == "" { + continue + } + s = strings.ToUpper(s) + if u, err := currency.ParseISO(s); err == nil { + valid = append(valid, u.String()) + } } - - return "", fmt.Errorf("failed to find matching imp for bid %s", imp.ID) + if len(valid) == 0 { + return []string{currencyUSD} + } + return valid } -func GetMediaTypeForImp(reqImp openrtb2.Imp) openrtb_ext.BidType { - - if reqImp.Video != nil { +func getMediaType(imp openrtb2.Imp) openrtb_ext.BidType { + switch { + case imp.Video != nil: return openrtb_ext.BidTypeVideo - } - if reqImp.Audio != nil { + case imp.Audio != nil: return openrtb_ext.BidTypeAudio + case imp.Native != nil: + return openrtb_ext.BidTypeNative + default: + return openrtb_ext.BidTypeBanner } - return openrtb_ext.BidTypeBanner } diff --git a/adapters/resetdigital/resetdigital_test.go b/adapters/resetdigital/resetdigital_test.go index 9efba33f30..0bd5a35627 100644 --- a/adapters/resetdigital/resetdigital_test.go +++ b/adapters/resetdigital/resetdigital_test.go @@ -1,17 +1,23 @@ package resetdigital import ( + "encoding/json" + "net/http" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ - Endpoint: "https://test.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: "https://example.com", + }, config.Server{}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) @@ -19,3 +25,727 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "resetdigitaltest", bidder) } + +func TestValidateAndFilterCurrencies(t *testing.T) { + tests := []struct { + name string + input []string + expected []string + }{ + { + name: "empty array", + input: []string{}, + expected: []string{"USD"}, + }, + { + name: "nil array", + input: nil, + expected: []string{"USD"}, + }, + { + name: "single empty string", + input: []string{""}, + expected: []string{"USD"}, + }, + { + name: "multiple empty strings", + input: []string{"", ""}, + expected: []string{"USD"}, + }, + { + name: "whitespace only strings", + input: []string{" ", "\t", "\n"}, + expected: []string{"USD"}, + }, + { + name: "single valid currency", + input: []string{"EUR"}, + expected: []string{"EUR"}, + }, + { + name: "multiple valid currencies", + input: []string{"USD", "EUR", "GBP"}, + expected: []string{"USD", "EUR", "GBP"}, + }, + { + name: "single invalid currency", + input: []string{"INVALID"}, + expected: []string{"USD"}, + }, + { + name: "mixed valid and invalid currencies", + input: []string{"USD", "INVALID", "EUR"}, + expected: []string{"USD", "EUR"}, + }, + { + name: "currencies with whitespace", + input: []string{" USD ", "\tEUR\t", " GBP\n"}, + expected: []string{"USD", "EUR", "GBP"}, + }, + { + name: "lowercase currencies", + input: []string{"usd", "eur"}, + expected: []string{"USD", "EUR"}, + }, + { + name: "mixed case currencies", + input: []string{"Usd", "EUR", "gbp"}, + expected: []string{"USD", "EUR", "GBP"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := validateAndFilterCurrencies(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetMediaType(t *testing.T) { + tests := []struct { + name string + imp openrtb2.Imp + expected openrtb_ext.BidType + }{ + { + name: "Banner type", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + }, + expected: openrtb_ext.BidTypeBanner, + }, + { + name: "Video type", + imp: openrtb2.Imp{ + Video: &openrtb2.Video{}, + }, + expected: openrtb_ext.BidTypeVideo, + }, + { + name: "Audio type", + imp: openrtb2.Imp{ + Audio: &openrtb2.Audio{}, + }, + expected: openrtb_ext.BidTypeAudio, + }, + { + name: "Native type", + imp: openrtb2.Imp{ + Native: &openrtb2.Native{}, + }, + expected: openrtb_ext.BidTypeNative, + }, + { + name: "Multiple media types - prioritize video", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + Video: &openrtb2.Video{}, + }, + expected: openrtb_ext.BidTypeVideo, + }, + { + name: "Multiple media types - prioritize audio over banner", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + Audio: &openrtb2.Audio{}, + }, + expected: openrtb_ext.BidTypeAudio, + }, + { + name: "Multiple media types - prioritize native over banner", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + Native: &openrtb2.Native{}, + }, + expected: openrtb_ext.BidTypeNative, + }, + { + name: "No media type defaults to banner", + imp: openrtb2.Imp{}, + expected: openrtb_ext.BidTypeBanner, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := getMediaType(test.imp) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestGetBidType(t *testing.T) { + tests := []struct { + name string + bid openrtb2.Bid + request *openrtb2.BidRequest + expected openrtb_ext.BidType + hasError bool + }{ + { + name: "Banner MType", + bid: openrtb2.Bid{ + MType: openrtb2.MarkupBanner, + }, + request: &openrtb2.BidRequest{}, + expected: openrtb_ext.BidTypeBanner, + hasError: false, + }, + { + name: "Video MType", + bid: openrtb2.Bid{ + MType: openrtb2.MarkupVideo, + }, + request: &openrtb2.BidRequest{}, + expected: openrtb_ext.BidTypeVideo, + hasError: false, + }, + { + name: "Audio MType", + bid: openrtb2.Bid{ + MType: openrtb2.MarkupAudio, + }, + request: &openrtb2.BidRequest{}, + expected: openrtb_ext.BidTypeAudio, + hasError: false, + }, + { + name: "Native MType", + bid: openrtb2.Bid{ + MType: openrtb2.MarkupNative, + }, + request: &openrtb2.BidRequest{}, + expected: openrtb_ext.BidTypeNative, + hasError: false, + }, + { + name: "No MType, lookup impression - banner", + bid: openrtb2.Bid{ + ImpID: "imp-1", + }, + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Banner: &openrtb2.Banner{}, + }, + }, + }, + expected: openrtb_ext.BidTypeBanner, + hasError: false, + }, + { + name: "No MType, lookup impression - video", + bid: openrtb2.Bid{ + ImpID: "imp-1", + }, + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Video: &openrtb2.Video{}, + }, + }, + }, + expected: openrtb_ext.BidTypeVideo, + hasError: false, + }, + { + name: "No matching impression", + bid: openrtb2.Bid{ + ImpID: "imp-not-found", + }, + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Banner: &openrtb2.Banner{}, + }, + }, + }, + expected: "", + hasError: true, + }, + { + name: "Unknown MType falls back to impression lookup", + bid: openrtb2.Bid{ + ImpID: "imp-1", + MType: openrtb2.MarkupType(99), + }, + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Banner: &openrtb2.Banner{}, + }, + }, + }, + expected: openrtb_ext.BidTypeBanner, + hasError: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + bidType, err := getBidType(test.bid, test.request) + + if test.hasError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, test.expected, bidType) + } + }) + } +} + +func TestMakeBidsErrorCases(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ + Endpoint: "https://example.com", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + tests := []struct { + name string + responseData *adapters.ResponseData + expectNil bool + expectErrs int + errType interface{} + }{ + { + name: "Status 204 No Content", + responseData: &adapters.ResponseData{ + StatusCode: http.StatusNoContent, + }, + expectNil: true, + expectErrs: 0, + }, + { + name: "Status 400 Bad Request", + responseData: &adapters.ResponseData{ + StatusCode: http.StatusBadRequest, + Body: []byte(`{"error": "Bad Request"}`), + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadInput{}, + }, + { + name: "Status 500 Internal Server Error", + responseData: &adapters.ResponseData{ + StatusCode: http.StatusInternalServerError, + Body: []byte(`{"error": "Internal Server Error"}`), + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadServerResponse{}, + }, + { + name: "Invalid JSON response", + responseData: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{invalid json`), + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadServerResponse{}, + }, + { + name: "Empty seatbid array", + responseData: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test", "seatbid": []}`), + }, + expectNil: true, + expectErrs: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + request := &openrtb2.BidRequest{} + bidResponse, errs := bidder.MakeBids(request, &adapters.RequestData{}, test.responseData) + + if test.expectNil { + assert.Nil(t, bidResponse) + } else { + assert.NotNil(t, bidResponse) + } + + assert.Len(t, errs, test.expectErrs) + + if test.expectErrs > 0 && test.errType != nil { + assert.IsType(t, test.errType, errs[0]) + } + }) + } +} + +func TestMakeRequestsErrorCases(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ + Endpoint: "https://example.com", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + tests := []struct { + name string + request *openrtb2.BidRequest + expectNil bool + expectErrs int + errType interface{} + }{ + { + name: "Multiple impressions", + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + {ID: "imp1", Ext: json.RawMessage(`{"bidder": {"placement_id": "test"}}`)}, + {ID: "imp2", Ext: json.RawMessage(`{"bidder": {"placement_id": "test"}}`)}, + }, + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadInput{}, + }, + { + name: "Malformed imp.ext", + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{invalid json`), + }, + }, + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadInput{}, + }, + { + name: "Malformed bidder params", + request: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {invalid json}`), + }, + }, + }, + expectNil: true, + expectErrs: 1, + errType: &errortypes.BadInput{}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + reqs, errs := bidder.MakeRequests(test.request, &adapters.ExtraRequestInfo{}) + + if test.expectNil { + assert.Nil(t, reqs) + } else { + assert.NotNil(t, reqs) + } + + assert.Len(t, errs, test.expectErrs) + + if test.expectErrs > 0 && test.errType != nil { + assert.IsType(t, test.errType, errs[0]) + } + }) + } +} + +func TestParseBidResponseEdgeCases(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ + Endpoint: "https://example.com", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + tests := []struct { + name string + request *openrtb2.BidRequest + responseData *adapters.ResponseData + expectBids int + expectErrs int + }{ + { + name: "Bid with zero price filtered out", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + {ID: "test-imp-id", Banner: &openrtb2.Banner{}}, + }, + }, + responseData: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{ + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.0, + "adm": "<div>test ad</div>" + } + ] + } + ], + "cur": "USD" + }`), + }, + expectBids: 0, + expectErrs: 1, + }, + { + name: "Bid with negative price filtered out", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + {ID: "test-imp-id", Banner: &openrtb2.Banner{}}, + }, + }, + responseData: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{ + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": -1.5, + "adm": "<div>test ad</div>" + } + ] + } + ], + "cur": "USD" + }`), + }, + expectBids: 0, + expectErrs: 1, + }, + { + name: "Currency fallback to request currency", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Cur: []string{"EUR"}, + Imp: []openrtb2.Imp{ + {ID: "test-imp-id", Banner: &openrtb2.Banner{}}, + }, + }, + responseData: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{ + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>" + } + ] + } + ] + }`), + }, + expectBids: 1, + expectErrs: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + bidResponse, errs := bidder.MakeBids(test.request, &adapters.RequestData{}, test.responseData) + + if test.expectBids > 0 { + assert.NotNil(t, bidResponse) + assert.Len(t, bidResponse.Bids, test.expectBids) + } + + assert.Len(t, errs, test.expectErrs) + }) + } +} + +func TestSchainPassthrough(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ + Endpoint: "https://example.com", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + tests := []struct { + name string + request *openrtb2.BidRequest + expectSchain bool + expectedSchain *openrtb2.SupplyChain + }{ + { + name: "Request with schain should pass it through", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Source: &openrtb2.Source{ + TID: "test-transaction-id", + SChain: &openrtb2.SupplyChain{ + Complete: 1, + Ver: "1.0", + Nodes: []openrtb2.SupplyChainNode{ + { + ASI: "example.com", + SID: "12345", + HP: openrtb2.Int8Ptr(1), + RID: "request-id-123", + }, + }, + }, + }, + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"placement_id": "test-placement"}}`), + }, + }, + }, + expectSchain: true, + expectedSchain: &openrtb2.SupplyChain{ + Complete: 1, + Ver: "1.0", + Nodes: []openrtb2.SupplyChainNode{ + { + ASI: "example.com", + SID: "12345", + HP: openrtb2.Int8Ptr(1), + RID: "request-id-123", + }, + }, + }, + }, + { + name: "Request without schain should not include it", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Source: &openrtb2.Source{ + TID: "test-transaction-id", + }, + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"placement_id": "test-placement"}}`), + }, + }, + }, + expectSchain: false, + expectedSchain: nil, + }, + { + name: "Request without source should not include schain", + request: &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"placement_id": "test-placement"}}`), + }, + }, + }, + expectSchain: false, + expectedSchain: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + reqs, errs := bidder.MakeRequests(test.request, &adapters.ExtraRequestInfo{}) + + assert.Empty(t, errs) + assert.Len(t, reqs, 1) + + var sentRequest openrtb2.BidRequest + err := json.Unmarshal(reqs[0].Body, &sentRequest) + assert.NoError(t, err) + + if test.expectSchain { + assert.NotNil(t, sentRequest.Source) + assert.NotNil(t, sentRequest.Source.SChain) + assert.Equal(t, test.expectedSchain.Complete, sentRequest.Source.SChain.Complete) + assert.Equal(t, test.expectedSchain.Ver, sentRequest.Source.SChain.Ver) + assert.Len(t, sentRequest.Source.SChain.Nodes, len(test.expectedSchain.Nodes)) + + if len(sentRequest.Source.SChain.Nodes) > 0 { + assert.Equal(t, test.expectedSchain.Nodes[0].ASI, sentRequest.Source.SChain.Nodes[0].ASI) + assert.Equal(t, test.expectedSchain.Nodes[0].SID, sentRequest.Source.SChain.Nodes[0].SID) + assert.Equal(t, test.expectedSchain.Nodes[0].HP, sentRequest.Source.SChain.Nodes[0].HP) + assert.Equal(t, test.expectedSchain.Nodes[0].RID, sentRequest.Source.SChain.Nodes[0].RID) + } + } else { + if sentRequest.Source != nil { + assert.Nil(t, sentRequest.Source.SChain) + } + } + }) + } +} + +func TestSourceFieldsPassthrough(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderResetDigital, config.Adapter{ + Endpoint: "https://example.com", + }, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Source: &openrtb2.Source{ + TID: "test-transaction-id", + FD: openrtb2.Int8Ptr(1), + Ext: json.RawMessage(`{"custom": "data"}`), + }, + Imp: []openrtb2.Imp{ + { + ID: "test-imp-id", + Ext: json.RawMessage(`{"bidder": {"placement_id": "test-placement"}}`), + }, + }, + } + + reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + assert.Empty(t, errs) + assert.Len(t, reqs, 1) + + var sentRequest openrtb2.BidRequest + err := json.Unmarshal(reqs[0].Body, &sentRequest) + assert.NoError(t, err) + + assert.NotNil(t, sentRequest.Source) + assert.Equal(t, "test-transaction-id", sentRequest.Source.TID) + assert.Equal(t, openrtb2.Int8Ptr(1), sentRequest.Source.FD) + + var expectedExt, actualExt map[string]interface{} + err = json.Unmarshal([]byte(`{"custom": "data"}`), &expectedExt) + assert.NoError(t, err) + err = json.Unmarshal(sentRequest.Source.Ext, &actualExt) + assert.NoError(t, err) + assert.Equal(t, expectedExt, actualExt) +} diff --git a/adapters/resetdigital/resetdigitaltest/exemplary/simple-audio.json b/adapters/resetdigital/resetdigitaltest/exemplary/simple-audio.json index d032b4c6f3..38a44e8cf2 100644 --- a/adapters/resetdigital/resetdigitaltest/exemplary/simple-audio.json +++ b/adapters/resetdigital/resetdigitaltest/exemplary/simple-audio.json @@ -1,155 +1,82 @@ { "mockBidRequest": { - "id": "12345", - "at": 1, - "bcat": [ - "IAB24", - "IAB25", - "IAB26" - ], - "cur": [ - "USD" - ], - "source": { - "fd": 0, - "tid": "00000FBCE10DE8FA", - "schain": { - "complete": 1, - "ver": "1.0", - "nodes": [ - { - "asi": "resetdigital.co", - "sid": "176", - "hp": 1 - } - ] - } - }, - "device": { - "ip": "35.146.176.97", - "js": 1, - "language": "en", - "ua": "PostmanRuntime/7.42.0" - }, - "user": { - "id": "000011200BA1065C", - "buyeruid": "000011200BA1065C" - }, - "app": { - "id": "test.com", - "bundle": "test.com", - "name": "test.com", - "content": { - "livestream": 1, - "genre": "F%C3%BAtbol", - "cat": [ - "" - ], - "language": "es" - }, - "publisher": { - "id": "176" - }, - "keywords": "" - }, + "id": "test-audio-request-id", "imp": [ { - "id": "001", - "bidfloor": 1.429, - "tagid": "667", - "secure": 1, + "id": "test-audio-imp-id", "audio": { - "protocols": [ - 2, - 3, - 5, - 6 - ], - "mimes": [ - "audio/mp4", - "audio/mp3" - ], - "api": [], - "minduration": 15, - "maxduration": 60, - "startdelay": -1 + "mimes": ["audio/mpeg"], + "minduration": 5, + "maxduration": 30 }, "ext": { "bidder": { - "placement_id": "placement-id-1" + "placement_id": "test-audio-placement" } } } ], "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 400 + "page": "https://example.com/audio", + "domain": "example.com" + } }, "httpCalls": [ { "expectedRequest": { - "method": "POST", + "uri": "https://example.com?pid=test-audio-placement", "body": { - "imps": [ + "id": "test-audio-request-id", + "imp": [ { - "bid_id": "12345", - "ext": { - "gpid": "" + "id": "test-audio-imp-id", + "audio": { + "mimes": ["audio/mpeg"], + "minduration": 5, + "maxduration": 30 }, - "imp_id": "001", - "media_types": { - "banner": {}, - "video": {}, - "audio": { - "mimes": [ - "audio/mp4", - "audio/mp3" - ] + "tagid": "test-audio-placement", + "ext": { + "bidder": { + "placement_id": "test-audio-placement" } - }, - "zone_id": { - "placementId": "placement-id-1" } } ], "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } + "page": "https://example.com/audio", + "domain": "example.com" + }, + "cur": ["USD"] + }, + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"], + "X-OpenRTB-Version": ["2.6"] }, - "impIDs": [ - "001" - ] + "impIDs": ["test-audio-imp-id"] }, "mockResponse": { "status": 200, "body": { - "bids": [ + "id": "test-audio-request-id", + "seatbid": [ { - "bid_id": "01", - "imp_id": "001", - "cpm": 9.11, - "dealid": "RD-1000164", - "cid": "1000048-1002918", - "crid": "1003893", - "adid": "1003893", - "language": "en", - "w": "0", - "h": "0", - "seat": "resetdigital", - "html": "test markup" + "bid": [ + { + "id": "test-audio-bid-id", + "impid": "test-audio-imp-id", + "price": 4.2, + "adm": "<VAST version=\"3.0\"><Ad id=\"a1\"></Ad></VAST>", + "crid": "test-audio-creative-id", + "adomain": ["example.com"], + "mtype": 3 + } + ], + "seat": "resetdigital" } - ] + ], + "cur": "USD" } } } @@ -160,12 +87,13 @@ "bids": [ { "bid": { - "adm": "test markup", - "cid": "1000048-1002918", - "crid": "1003893", - "id": "01", - "impid": "001", - "price": 9.11 + "id": "test-audio-bid-id", + "impid": "test-audio-imp-id", + "price": 4.2, + "adm": "<VAST version=\"3.0\"><Ad id=\"a1\"></Ad></VAST>", + "crid": "test-audio-creative-id", + "adomain": ["example.com"], + "mtype": 3 }, "type": "audio", "seat": "resetdigital" @@ -173,4 +101,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/resetdigital/resetdigitaltest/exemplary/simple-banner.json b/adapters/resetdigital/resetdigitaltest/exemplary/simple-banner.json index 2a0fcacd55..22a0584e9c 100644 --- a/adapters/resetdigital/resetdigitaltest/exemplary/simple-banner.json +++ b/adapters/resetdigital/resetdigitaltest/exemplary/simple-banner.json @@ -1,101 +1,120 @@ { "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } } } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 + "site": { + "page": "https://example.com", + "domain": "example.com" + } }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } ] - ] - }, - "audio": {}, - "video": {} + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com", + "domain": "example.com" }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } + "cur": [ + "USD" + ] + }, + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ], + "X-OpenRTB-Version": [ + "2.6" + ] + }, + "impIDs": ["test-imp-id"] }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }] + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.14, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250, + "adomain": ["example.com"] + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } } } - }], - - "expectedBidResponses": [{ - "currency": "USD", - "bids": [{ - "bid": { - "adm": "test markup", - "cid": "1002088", - "crid": "1000763-1002088", - "id": "01", - "impid": "001", - "price": 1.00, - "w": 300, - "h": 250 - }, - "type": "banner", - "seat": "resetdigital" - }] - }] + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.14, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250, + "adomain": ["example.com"] + }, + "type": "banner", + "seat": "resetdigital" + } + ] + } + ] } diff --git a/adapters/resetdigital/resetdigitaltest/exemplary/simple-video.json b/adapters/resetdigital/resetdigitaltest/exemplary/simple-video.json deleted file mode 100644 index ce4e1916fd..0000000000 --- a/adapters/resetdigital/resetdigitaltest/exemplary/simple-video.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [ - { - "id": "001", - "video": { - "w": 900, - "h": 250, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - } - ], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "POST", - "body": { - "imps": [ - { - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": {}, - "video": { - "sizes": [ - [ - 900, - 250 - ] - ], - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - } - ], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [ - { - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "900", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - } - ] - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "adm": "test markup", - "cid": "1002088", - "crid": "1000763-1002088", - "id": "01", - "impid": "001", - "price": 1.00, - "w": 900, - "h": 250 - }, - "type": "video", - "seat": "resetdigital" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-bidder.json b/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-bidder.json new file mode 100644 index 0000000000..2e538cb024 --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-bidder.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": 1 + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Error parsing bidderExt from imp.ext:", + "comparison": "regex" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-resetdigital.json b/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-resetdigital.json new file mode 100644 index 0000000000..428bbdee22 --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/bad-ext-resetdigital.json @@ -0,0 +1,32 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 123 + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Error parsing resetDigitalExt from bidderExt.bidder:", + "comparison": "regex" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/bad-response-body.json b/adapters/resetdigital/resetdigitaltest/supplemental/bad-response-body.json new file mode 100644 index 0000000000..c4aa6c727b --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/bad-response-body.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": 123 + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad server response:", + "comparison": "regex" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/currency-fallback.json b/adapters/resetdigital/resetdigitaltest/supplemental/currency-fallback.json new file mode 100644 index 0000000000..c4757d6588 --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/currency-fallback.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": ["EUR"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "EUR" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + } + ], + "seat": "resetdigital" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/empty-response.json b/adapters/resetdigital/resetdigitaltest/supplemental/empty-response.json new file mode 100644 index 0000000000..f83460632f --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/empty-response.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-empty-request-id", + "imp": [ + { + "id": "test-empty-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-no-bids-placement" + } + } + } + ], + "site": { + "page": "https://example.com/empty", + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-no-bids-placement", + "body": { + "id": "test-empty-request-id", + "imp": [ + { + "id": "test-empty-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-no-bids-placement", + "ext": { + "bidder": { + "placement_id": "test-no-bids-placement" + } + } + } + ], + "site": { + "page": "https://example.com/empty", + "domain": "example.com" + }, + "cur": [ + "USD" + ] + }, + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ], + "X-OpenRTB-Version": [ + "2.6" + ] + }, + "impIDs": ["test-empty-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/imp-id-mismatch.json b/adapters/resetdigital/resetdigitaltest/supplemental/imp-id-mismatch.json deleted file mode 100644 index a763e88561..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/imp-id-mismatch.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "999", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }] - } - } - }], - - "expectedMakeBidsErrors": [ - { - "value": "no matching impression found for ImpID 999", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-height.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-height.json deleted file mode 100644 index d1c40ffaba..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-height.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "123456789012345678901234567890123456789012345678901234567890", - "seat": "resetdigital", - "html": "test markup" - }] - } - } - }], - - "expectedMakeBidsErrors": [ - { - "value": "strconv.ParseInt: parsing \"123456789012345678901234567890123456789012345678901234567890\": value out of range", - "comparison": "literal" - } - ], - "expectedBidResponses": [] -} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-width.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-width.json deleted file mode 100644 index 8c118bfecd..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-bid-width.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "123456789012345678901234567890123456789012345678901234567890", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }] - } - } - }], - - "expectedMakeBidsErrors": [ - { - "value": "strconv.ParseInt: parsing \"123456789012345678901234567890123456789012345678901234567890\": value out of range", - "comparison": "literal" - } - ], - "expectedBidResponses": [] -} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-cur.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-cur.json deleted file mode 100644 index 3dcf7a7656..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-cur.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-invalid-cur", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - } - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "test-invalid-cur", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 400, - "body": { - "error": "Unexpected status code: 400. Run with request.debug = 1 for more info" - } - } - }], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-device.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-device.json deleted file mode 100644 index 7b0fc8c264..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-device.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-invalid-device", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ] - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "test-invalid-device", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 400, - "body": { - "error": "Unexpected status code: 400. Run with request.debug = 1 for more info" - } - } - }], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-media-def.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-media-def.json deleted file mode 100644 index 0c24e666b9..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-media-def.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500, - "debug": 1 - }, - "httpCalls": [], - "expectedMakeRequestsErrors": [ - { - "value": "failed to find matching imp for bid 001", - "comparison": "literal" - } - ], - "expectedBidResponses": [] - } \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-placement-id.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-placement-id.json deleted file mode 100644 index 14959b36d1..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-placement-id.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "video": { - "w": 900, - "h": 250, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "placement_id": 1 - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500, - "debug": 1 - }, - "httpCalls": [], - "expectedMakeRequestsErrors": [ - { - "value": "json: cannot unmarshal number into Go struct field ImpExtResetDigital.placement_id of type string", - "comparison": "literal" - } - ], - "expectedBidResponses": [] - } diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-video-dim.json b/adapters/resetdigital/resetdigitaltest/supplemental/invalid-video-dim.json deleted file mode 100644 index 4e1f43d13f..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/invalid-video-dim.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "video": { - "w": 0, - "h": 480, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500, - "debug": 1 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": {}, - "video": { - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 204, - "body": { - "error": "Unexpected status code: 204. Run with request.debug = 1 for more info" - } - } - }], - "expectedBidResponses": [] - } diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/malformed-response.json b/adapters/resetdigital/resetdigitaltest/supplemental/malformed-response.json deleted file mode 100644 index 4a063d0843..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/malformed-response.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": "malformed body!" - } - }], - - "expectedMakeBidsErrors": [ - { - "value": "json: cannot unmarshal string into Go value of type resetdigital.resetDigitalBidResponse", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/missing-currency.json b/adapters/resetdigital/resetdigitaltest/supplemental/missing-currency.json deleted file mode 100644 index bd438f7857..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/missing-currency.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }] - } - } - }], - - "expectedBidResponses": [{ - "currency": "USD", - "bids": [{ - "bid": { - "adm": "test markup", - "cid": "1002088", - "crid": "1000763-1002088", - "id": "01", - "impid": "001", - "price": 1.00, - "w": 300, - "h": 250 - }, - "type": "banner", - "seat": "resetdigital" - }] - }] -} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/mtype-audio.json b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-audio.json new file mode 100644 index 0000000000..2b790feee4 --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-audio.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [2, 3, 5, 6] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [2, 3, 5, 6] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.8, + "adm": "<VAST></VAST>", + "crid": "test-creative-id", + "mtype": 3 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.8, + "adm": "<VAST></VAST>", + "crid": "test-creative-id", + "mtype": 3 + }, + "type": "audio", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/mtype-banner.json b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-banner.json new file mode 100644 index 0000000000..25f1ad849b --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-banner.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/mtype-native.json b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-native.json new file mode 100644 index 0000000000..3e6347322d --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-native.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":80}}]}" + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":80}}]}" + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}]}}", + "crid": "test-creative-id", + "mtype": 4 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}]}}", + "crid": "test-creative-id", + "mtype": 4 + }, + "type": "native", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/mtype-video.json b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-video.json new file mode 100644 index 0000000000..0589a8da5b --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/mtype-video.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<VAST></VAST>", + "crid": "test-creative-id", + "w": 640, + "h": 480, + "mtype": 2 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<VAST></VAST>", + "crid": "test-creative-id", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/multi-format.json b/adapters/resetdigital/resetdigitaltest/supplemental/multi-format.json deleted file mode 100644 index 4de554752f..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/multi-format.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-multi-format", - "imp": [{ - "id": "001", - "banner": { - "w": 300, - "h": 600 - }, - "video": { - "w": 900, - "h": 250, - "mimes": ["video/mp4"] - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "test-multi-format", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 300, - 600 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "<script src=\"https://data.resetdigital.co/evts?S0B=1&R0E=1&R0M=3_3&testad=US-HEADER-04&R0A=1000048_1001096_1001117_1627360746&R0P=resetio_1234_muscleandfitness.com_Site_1_Banner&R0L=*_*_*_*_*&R0D=*_*_*_*_*_*&R0B=*_*_*\" type=\"text/javascript\"></script><image src='https://adsreq.resetdigital.co?brid=0000000000000001' /><image src='https://sync2.resetdigital.co/hbsync?ck=0000000000000001' />" - }] - } - } - }], - - "expectedBidResponses": [{ - "currency": "USD", - "bids": [{ - "bid": { - "adm": "<script src=\"https://data.resetdigital.co/evts?S0B=1&R0E=1&R0M=3_3&testad=US-HEADER-04&R0A=1000048_1001096_1001117_1627360746&R0P=resetio_1234_muscleandfitness.com_Site_1_Banner&R0L=*_*_*_*_*&R0D=*_*_*_*_*_*&R0B=*_*_*\" type=\"text/javascript\"></script><image src='https://adsreq.resetdigital.co?brid=0000000000000001' /><image src='https://sync2.resetdigital.co/hbsync?ck=0000000000000001' />", - "cid": "1002088", - "crid": "1000763-1002088", - "id": "01", - "impid": "001", - "price": 1.00, - "w": 300, - "h": 250 - }, - "type": "video", - "seat": "resetdigital" - }] - }] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/multiple-bids.json b/adapters/resetdigital/resetdigitaltest/supplemental/multiple-bids.json deleted file mode 100644 index 8892994d73..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/multiple-bids.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "mockBidRequest": { - "id": "12345", - "imp": [{ - "id": "001", - "banner": { - "h": 300, - "w": 250 - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ], - "device": { - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "ip": "127.0.0.1", - "language": "EN" - }, - "tmax": 500 - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "12345", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": { - "sizes": [ - [ - 250, - 300 - ] - ] - }, - "video": {}, - "audio": {} - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "bids": [{ - "bid_id": "01", - "imp_id": "001", - "cpm": 1.00, - "cid": "1002088", - "crid": "1000763-1002088", - "adid": "1002088", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }, - { - "bid_id": "02", - "imp_id": "001", - "cpm": 1.10, - "cid": "1002089", - "crid": "1000763-1002089", - "adid": "1002089", - "w": "300", - "h": "250", - "seat": "resetdigital", - "html": "test markup" - }] - } - } - }], - - "expectedMakeBidsErrors": [ - { - "value": "expected exactly one bid in the response, but got 2", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/multiple-imp-error.json b/adapters/resetdigital/resetdigitaltest/supplemental/multiple-imp-error.json new file mode 100644 index 0000000000..81ee3ec8df --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/multiple-imp-error.json @@ -0,0 +1,49 @@ +{ + "mockBidRequest": { + "id": "test-multi-request-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-banner-placement" + } + } + }, + { + "id": "test-imp-video-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "linearity": 1, + "maxduration": 30 + }, + "ext": { + "bidder": { + "placement_id": "test-video-placement" + } + } + } + ], + "site": { + "page": "https://example.com/multi", + "domain": "example.com" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "ResetDigital adapter supports only one impression per request", + "comparison": "literal" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/native-mediatype.json b/adapters/resetdigital/resetdigitaltest/supplemental/native-mediatype.json new file mode 100644 index 0000000000..13a660cf6b --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/native-mediatype.json @@ -0,0 +1,91 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":80}}]}" + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":80}}]}" + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}]}}", + "crid": "test-creative-id" + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}]}}", + "crid": "test-creative-id" + }, + "type": "native", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/no-matching-impression.json b/adapters/resetdigital/resetdigitaltest/supplemental/no-matching-impression.json new file mode 100644 index 0000000000..64656b0b4f --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/no-matching-impression.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "wrong-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "no matching impression found for ImpID: wrong-imp-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/status-400.json b/adapters/resetdigital/resetdigitaltest/supplemental/status-400.json new file mode 100644 index 0000000000..435182924d --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/status-400.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/status-500.json b/adapters/resetdigital/resetdigitaltest/supplemental/status-500.json new file mode 100644 index 0000000000..e151f38500 --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/status-500.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-placement", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-placement", + "ext": { + "bidder": { + "placement_id": "test-placement" + } + } + } + ], + "site": { + "page": "https://example.com" + }, + "cur": [ + "USD" + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/unknown-media.json b/adapters/resetdigital/resetdigitaltest/supplemental/unknown-media.json deleted file mode 100644 index 5d9fb57363..0000000000 --- a/adapters/resetdigital/resetdigitaltest/supplemental/unknown-media.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-unknown-media-type", - "imp": [{ - "id": "001", - "audio": { - "mimes": ["audio/mpeg"] - }, - "ext": { - "bidder": { - "placement_id": "placement-id-1" - } - } - }], - "site": { - "domain": "https://test.com", - "page": "https://test.com/2016/06/12" - }, - "cur": [ - "USD" - ] - }, - "httpCalls": [{ - "expectedRequest": { - "method": "POST", - "body": { - "imps": [{ - "bid_id": "test-unknown-media-type", - "ext": { - "gpid": "" - }, - "imp_id": "001", - "media_types": { - "banner": {}, - "video": {}, - "audio": { - "mimes": ["audio/mpeg"] - } - }, - "zone_id": { - "placementId": "placement-id-1" - } - }], - "site": { - "domain": "https://test.com", - "referrer": "https://test.com/2016/06/12" - } - }, - "impIDs": [ - "001" - ] - }, - "mockResponse": { - "status": 400, - "body": { - "error": "unknown media type for bid imp ID 003" - } - } - }], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/resetdigital/resetdigitaltest/supplemental/zero-price-bid.json b/adapters/resetdigital/resetdigitaltest/supplemental/zero-price-bid.json new file mode 100644 index 0000000000..eab76ee66a --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/supplemental/zero-price-bid.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-zero-price-request-id", + "imp": [ + { + "id": "test-zero-price-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placement_id": "test-zero-price-placement" + } + } + } + ], + "site": { + "page": "https://example.com/zero-price", + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-zero-price-placement", + "body": { + "id": "test-zero-price-request-id", + "imp": [ + { + "id": "test-zero-price-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-zero-price-placement", + "ext": { + "bidder": { + "placement_id": "test-zero-price-placement" + } + } + } + ], + "site": { + "page": "https://example.com/zero-price", + "domain": "example.com" + }, + "cur": [ + "USD" + ] + }, + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ], + "X-OpenRTB-Version": [ + "2.6" + ] + }, + "impIDs": ["test-zero-price-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-zero-price-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-zero-price-bid-id", + "impid": "test-zero-price-imp-id", + "price": 0.0, + "adm": "<div>test zero price ad</div>", + "crid": "test-zero-price-creative-id", + "w": 300, + "h": 250, + "adomain": ["example.com"] + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "price 0.000000 <= 0 filtered out", + "comparison": "literal" + } + ] +} diff --git a/adapters/resetdigital/resetdigitaltest/video/simple-video.json b/adapters/resetdigital/resetdigitaltest/video/simple-video.json new file mode 100644 index 0000000000..fc62f5d85d --- /dev/null +++ b/adapters/resetdigital/resetdigitaltest/video/simple-video.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-video-request-id", + "imp": [ + { + "id": "test-video-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "linearity": 1, + "maxduration": 30 + }, + "ext": { + "bidder": { + "placement_id": "test-video-placement" + } + } + } + ], + "site": { + "page": "https://example.com/video", + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com?pid=test-video-placement", + "body": { + "id": "test-video-request-id", + "imp": [ + { + "id": "test-video-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "linearity": 1, + "maxduration": 30 + }, + "tagid": "test-video-placement", + "ext": { + "bidder": { + "placement_id": "test-video-placement" + } + } + } + ], + "site": { + "page": "https://example.com/video", + "domain": "example.com" + }, + "cur": [ + "USD" + ] + }, + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ], + "X-OpenRTB-Version": [ + "2.6" + ] + }, + "impIDs": ["test-video-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-video-bid-id", + "impid": "test-video-imp-id", + "price": 5.01, + "adm": "<VAST version=\"3.0\"><Ad id=\"123\"></Ad></VAST>", + "crid": "test-video-creative-id", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "mtype": 2 + } + ], + "seat": "resetdigital" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-video-bid-id", + "impid": "test-video-imp-id", + "price": 5.01, + "adm": "<VAST version=\"3.0\"><Ad id=\"123\"></Ad></VAST>", + "crid": "test-video-creative-id", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "mtype": 2 + }, + "type": "video", + "seat": "resetdigital" + } + ] + } + ] +} diff --git a/static/bidder-info/resetdigital.yaml b/static/bidder-info/resetdigital.yaml index db4e70ae76..db85d114a3 100644 --- a/static/bidder-info/resetdigital.yaml +++ b/static/bidder-info/resetdigital.yaml @@ -1,14 +1,24 @@ -endpoint: http://b-us-east14.resetdigital.co:9001 +endpoint: https://prebid.resetdigital.co +endpointCompression: gzip maintainer: email: biddersupport@resetdigital.co +gvlVendorID: 1162 capabilities: site: mediaTypes: - - banner - - video - - audio -gvlVendorID: 1162 -userSync: + - banner + - video + - native + - audio + app: + mediaTypes: + - banner + - video + - native + - audio + +usersync: redirect: - url: https://sync.resetdigital.co/csync?redir={{.RedirectURL}} - userMacro: '$USER_ID' + url: "https://sync.resetdigital.co/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "$UID" + supportCORS: true diff --git a/static/bidder-params/resetdigital.json b/static/bidder-params/resetdigital.json index 4d0538893f..dc79816ce6 100644 --- a/static/bidder-params/resetdigital.json +++ b/static/bidder-params/resetdigital.json @@ -1,13 +1,15 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Reset Digital Adapter Params", - "description": "A schema which validates params accepted by the Reset Digital adapter", - "type": "object", - "properties": { - "placement_id": { - "type": "string", - "minLength": 1, - "description": "Placement ID for the Reset Digital ad unit. This is the identifier for the ad unit on the Reset Digital platform, and its optional" - } + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "ResetDigital Adapter Params", + "description": "A schema which validates params accepted by the ResetDigital adapter", + "type": "object", + "properties": { + "placement_id": { + "type": "string", + "description": "Placement ID provided by ResetDigital", + "minLength": 1 } + }, + "required": ["placement_id"], + "additionalProperties": false } From 3fb0066c3c06c62861b0a9e6ed0b2c501f77137b Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Sat, 10 Jan 2026 23:21:36 +0200 Subject: [PATCH 142/272] Attekmi: Remove Vimayx alias (#4546) --- static/bidder-info/vimayx.yaml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 static/bidder-info/vimayx.yaml diff --git a/static/bidder-info/vimayx.yaml b/static/bidder-info/vimayx.yaml deleted file mode 100644 index 567d95c8c2..0000000000 --- a/static/bidder-info/vimayx.yaml +++ /dev/null @@ -1,2 +0,0 @@ -endpoint: "https://vimayx-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" -aliasOf: "smarthub" From 705eb8974030b29a90d74b30b08015d645b27001 Mon Sep 17 00:00:00 2001 From: sangarbe <sangarbe@gmail.com> Date: Sat, 10 Jan 2026 22:34:09 +0100 Subject: [PATCH 143/272] Seedtag: Set bid request currency to USD (#4615) --- adapters/seedtag/seedtag.go | 2 ++ adapters/seedtag/seedtagtest/exemplary/banner.json | 1 + adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json | 1 + adapters/seedtag/seedtagtest/exemplary/video.json | 1 + adapters/seedtag/seedtagtest/supplemental/invalid_mtype.json | 1 + .../seedtagtest/supplemental/response_unmarshal_error.json | 1 + .../seedtag/seedtagtest/supplemental/status_bad_request.json | 1 + .../seedtag/seedtagtest/supplemental/status_no_content.json | 1 + adapters/seedtag/seedtagtest/supplemental/status_not_ok.json | 1 + 9 files changed, 10 insertions(+) diff --git a/adapters/seedtag/seedtag.go b/adapters/seedtag/seedtag.go index 7836f2aaff..11e21699c2 100644 --- a/adapters/seedtag/seedtag.go +++ b/adapters/seedtag/seedtag.go @@ -51,6 +51,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } requestCopy := *request + // Set the CUR of bid to USD after converting all floors + requestCopy.Cur = []string{"USD"} requestCopy.Imp = imps requestJSON, err := jsonutil.Marshal(requestCopy) if err != nil { diff --git a/adapters/seedtag/seedtagtest/exemplary/banner.json b/adapters/seedtag/seedtagtest/exemplary/banner.json index 8e390c4134..3493131ab7 100644 --- a/adapters/seedtag/seedtagtest/exemplary/banner.json +++ b/adapters/seedtag/seedtagtest/exemplary/banner.json @@ -39,6 +39,7 @@ "Accept": ["application/json"] }, "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json b/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json index de0991c1e6..c109875df4 100644 --- a/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json +++ b/adapters/seedtag/seedtagtest/exemplary/bidfloor_converted.json @@ -53,6 +53,7 @@ "Accept": ["application/json"] }, "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/exemplary/video.json b/adapters/seedtag/seedtagtest/exemplary/video.json index 6bfbc52ad2..d8ac06fbbe 100644 --- a/adapters/seedtag/seedtagtest/exemplary/video.json +++ b/adapters/seedtag/seedtagtest/exemplary/video.json @@ -41,6 +41,7 @@ "Accept": ["application/json"] }, "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/supplemental/invalid_mtype.json b/adapters/seedtag/seedtagtest/supplemental/invalid_mtype.json index 636cb0ce97..ed830f90b4 100644 --- a/adapters/seedtag/seedtagtest/supplemental/invalid_mtype.json +++ b/adapters/seedtag/seedtagtest/supplemental/invalid_mtype.json @@ -37,6 +37,7 @@ "expectedRequest": { "uri": "http://url.seedtag.com", "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/supplemental/response_unmarshal_error.json b/adapters/seedtag/seedtagtest/supplemental/response_unmarshal_error.json index de60e366d4..f61a38f3c0 100644 --- a/adapters/seedtag/seedtagtest/supplemental/response_unmarshal_error.json +++ b/adapters/seedtag/seedtagtest/supplemental/response_unmarshal_error.json @@ -37,6 +37,7 @@ "expectedRequest": { "uri": "http://url.seedtag.com", "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/supplemental/status_bad_request.json b/adapters/seedtag/seedtagtest/supplemental/status_bad_request.json index 8cd058864e..27185ea89a 100644 --- a/adapters/seedtag/seedtagtest/supplemental/status_bad_request.json +++ b/adapters/seedtag/seedtagtest/supplemental/status_bad_request.json @@ -29,6 +29,7 @@ "expectedRequest": { "uri": "http://url.seedtag.com", "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/supplemental/status_no_content.json b/adapters/seedtag/seedtagtest/supplemental/status_no_content.json index aa415e17ed..b9aeff0796 100644 --- a/adapters/seedtag/seedtagtest/supplemental/status_no_content.json +++ b/adapters/seedtag/seedtagtest/supplemental/status_no_content.json @@ -29,6 +29,7 @@ "expectedRequest": { "uri": "http://url.seedtag.com", "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { diff --git a/adapters/seedtag/seedtagtest/supplemental/status_not_ok.json b/adapters/seedtag/seedtagtest/supplemental/status_not_ok.json index a5d8f80b41..20b2eb2600 100644 --- a/adapters/seedtag/seedtagtest/supplemental/status_not_ok.json +++ b/adapters/seedtag/seedtagtest/supplemental/status_not_ok.json @@ -29,6 +29,7 @@ "expectedRequest": { "uri": "http://url.seedtag.com", "body": { + "cur": ["USD"], "id": "test-request-id", "imp": [ { From ee641a0cb812f31556ca5f8fe0ec467af2171cde Mon Sep 17 00:00:00 2001 From: Hasan Kanjee <55110940+hasan-kanjee@users.noreply.github.com> Date: Sat, 10 Jan 2026 16:46:35 -0500 Subject: [PATCH 144/272] Flipp: Update endpoint to not use cdn (#4621) --- static/bidder-info/flipp.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/flipp.yaml b/static/bidder-info/flipp.yaml index 431c134579..01772ab41e 100644 --- a/static/bidder-info/flipp.yaml +++ b/static/bidder-info/flipp.yaml @@ -1,4 +1,4 @@ -endpoint: "https://cdn-gateflipp.flippback.com/flyer-locator-service/prebid_campaigns" +endpoint: "https://ads-flipp.com/flyer-locator-service/prebid_campaigns" maintainer: email: prebid@flipp.com capabilities: From a57a3acd89d893841e0723bf737d05cdafe56fab Mon Sep 17 00:00:00 2001 From: dev-adverxo <developer@adverxo.com> Date: Sat, 10 Jan 2026 23:22:40 +0100 Subject: [PATCH 145/272] Adverxo: Remove Mobupps alias (#4323) --- static/bidder-info/mobupps.yaml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 static/bidder-info/mobupps.yaml diff --git a/static/bidder-info/mobupps.yaml b/static/bidder-info/mobupps.yaml deleted file mode 100644 index bb35990b80..0000000000 --- a/static/bidder-info/mobupps.yaml +++ /dev/null @@ -1,9 +0,0 @@ -endpoint: "https://mobupps.pbsadverxo.com/auction?id={{.AdUnit}}&auth={{.TokenID}}" -aliasOf: "adverxo" -userSync: - iframe: - url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} - userMacro: $UID - redirect: - url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} - userMacro: $UID From 3a5c5ef219082859f017d14e1c00a4c232a96d18 Mon Sep 17 00:00:00 2001 From: optidigital-prebid <124287395+optidigital-prebid@users.noreply.github.com> Date: Sun, 11 Jan 2026 04:24:30 +0100 Subject: [PATCH 146/272] Optidigital: Add GPP support to user sync (#4646) Co-authored-by: Victor Gonzalez <victor@optidigital.com> --- static/bidder-info/optidigital.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/optidigital.yaml b/static/bidder-info/optidigital.yaml index b0df8a5ef8..30074e3a6f 100644 --- a/static/bidder-info/optidigital.yaml +++ b/static/bidder-info/optidigital.yaml @@ -19,5 +19,5 @@ userSync: supports: - iframe iframe: - url: "https://scripts.opti-digital.com/js/presyncs2s.html?endpoint=optidigital&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir={{.RedirectURL}}" + url: "https://scripts.opti-digital.com/js/presyncs2s.html?endpoint=optidigital&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" userMacro: "$UID" \ No newline at end of file From 7816fe214131ff53d672fbfd71f6f63bd242773d Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Sun, 11 Jan 2026 05:43:06 +0200 Subject: [PATCH 147/272] New Adapter: RadiantFusion - Attekmi alias (#4616) --- static/bidder-info/radiantfusion.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/radiantfusion.yaml diff --git a/static/bidder-info/radiantfusion.yaml b/static/bidder-info/radiantfusion.yaml new file mode 100644 index 0000000000..583fa8762a --- /dev/null +++ b/static/bidder-info/radiantfusion.yaml @@ -0,0 +1,2 @@ +endpoint: "https://radiantfusion-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +aliasOf: "smarthub" From efd6f99fc937a3f57d860bc4fd214e9a8ffc060f Mon Sep 17 00:00:00 2001 From: dtbarne <7635750+dtbarne@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:56:55 -0600 Subject: [PATCH 148/272] Mobilefuse: Add site media types (#4613) --- static/bidder-info/mobilefuse.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/bidder-info/mobilefuse.yaml b/static/bidder-info/mobilefuse.yaml index 14e488d077..c0770d80c2 100644 --- a/static/bidder-info/mobilefuse.yaml +++ b/static/bidder-info/mobilefuse.yaml @@ -12,6 +12,11 @@ capabilities: - banner - video - native + site: + mediaTypes: + - banner + - video + - native endpointCompression: "GZIP" openrtb: version: 2.6 From ed6ed552091dea61daf0a31b11c4503de8f13936 Mon Sep 17 00:00:00 2001 From: bidfuse <github@bidfuse.com> Date: Sun, 11 Jan 2026 06:11:14 +0200 Subject: [PATCH 149/272] New Adapter: Bidfuse (#4532) Co-authored-by: Kanceliarenko <kostiantyn.k@teqblaze.com> --- static/bidder-info/bidfuse.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 static/bidder-info/bidfuse.yaml diff --git a/static/bidder-info/bidfuse.yaml b/static/bidder-info/bidfuse.yaml new file mode 100644 index 0000000000..c993e2f184 --- /dev/null +++ b/static/bidder-info/bidfuse.yaml @@ -0,0 +1,11 @@ +aliasOf: "teqblaze" +endpoint: "https://bn.bidfuse.com/pserver" +maintainer: + email: "support@bidfuse.com" +userSync: + redirect: + url: "https://syncbf.bidfuse.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://syncbf.bidfuse.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file From d0cd97ee6aba99e9990e0f379c1ede8ed0df5b46 Mon Sep 17 00:00:00 2001 From: guscarreon <guscarreon@gmail.com> Date: Wed, 14 Jan 2026 22:20:49 -0500 Subject: [PATCH 150/272] Metrics: Standardize adapter connection metrics names (#4549) --- config/config.go | 4 ++-- config/config_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index eae0d981d3..e8f23b4ace 100644 --- a/config/config.go +++ b/config/config.go @@ -595,7 +595,7 @@ type DisabledMetrics struct { AdapterConnectionMetrics bool `mapstructure:"adapter_connections_metrics"` // True if we don't want to collect metrics on dial time and dial errors - AdapterConnectionDialMetrics bool `mapstructure:"adapter_connection_dial_metrics"` + AdapterConnectionDialMetrics bool `mapstructure:"adapter_connections_dial_metrics"` // True if we don't want to collect the per adapter buyer UID scrubbed metric AdapterBuyerUIDScrubbed bool `mapstructure:"adapter_buyeruid_scrubbed"` @@ -999,7 +999,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("metrics.disabled_metrics.account_debug", true) v.SetDefault("metrics.disabled_metrics.account_stored_responses", true) v.SetDefault("metrics.disabled_metrics.adapter_connections_metrics", true) - v.SetDefault("metrics.disabled_metrics.adapter_connection_dial_metrics", true) + v.SetDefault("metrics.disabled_metrics.adapter_connections_dial_metrics", true) v.SetDefault("metrics.disabled_metrics.adapter_buyeruid_scrubbed", true) v.SetDefault("metrics.disabled_metrics.adapter_gdpr_request_blocked", false) v.SetDefault("metrics.influxdb.host", "") diff --git a/config/config_test.go b/config/config_test.go index 3d7a0408b3..7d7ebe9101 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -158,7 +158,7 @@ func TestDefaults(t *testing.T) { cmpBools(t, "account_debug", true, cfg.Metrics.Disabled.AccountDebug) cmpBools(t, "account_stored_responses", true, cfg.Metrics.Disabled.AccountStoredResponses) cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) - cmpBools(t, "adapter_connection_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) + cmpBools(t, "adapter_connections_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) cmpBools(t, "adapter_buyeruid_scrubbed", true, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) cmpBools(t, "adapter_gdpr_request_blocked", false, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) cmpStrings(t, "certificates_file", "", cfg.PemCertsFile) @@ -484,7 +484,7 @@ metrics: account_debug: false account_stored_responses: false adapter_connections_metrics: true - adapter_connection_dial_metrics: true + adapter_connections_dial_metrics: true adapter_buyeruid_scrubbed: false adapter_gdpr_request_blocked: true account_modules_metrics: true @@ -921,7 +921,7 @@ func TestFullConfig(t *testing.T) { cmpBools(t, "account_debug", false, cfg.Metrics.Disabled.AccountDebug) cmpBools(t, "account_stored_responses", false, cfg.Metrics.Disabled.AccountStoredResponses) cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) - cmpBools(t, "adapter_connection_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) + cmpBools(t, "adapter_connections_dial_metrics", true, cfg.Metrics.Disabled.AdapterConnectionDialMetrics) cmpBools(t, "adapter_buyeruid_scrubbed", false, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) cmpBools(t, "adapter_gdpr_request_blocked", true, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) cmpStrings(t, "certificates_file", "/etc/ssl/cert.pem", cfg.PemCertsFile) From 16a0652fb288fea8674db67e0c61c931e7985e43 Mon Sep 17 00:00:00 2001 From: sangarbe <sangarbe@gmail.com> Date: Tue, 20 Jan 2026 16:27:36 +0100 Subject: [PATCH 151/272] Seedtag: Adds GPP macros on user sync url (#4465) --- static/bidder-info/seedtag.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/seedtag.yaml b/static/bidder-info/seedtag.yaml index 20df62ff0e..20dd7dfd5c 100644 --- a/static/bidder-info/seedtag.yaml +++ b/static/bidder-info/seedtag.yaml @@ -10,5 +10,5 @@ capabilities: - banner userSync: iframe: - url: "https://s.seedtag.com/cs/cookiesync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp_consent={{.USPrivacy}}&redirect={{.RedirectURL}}" + url: "https://s.seedtag.com/cs/cookiesync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp_consent={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" userMacro: "$UID" From 6dc102e5b3f1a4cd84efb14fa3813c7cc671e547 Mon Sep 17 00:00:00 2001 From: Aleksandar Crepuljarevic <a.crepuljarevic@gmail.com> Date: Wed, 28 Jan 2026 17:13:57 +0100 Subject: [PATCH 152/272] Ogury: Allow inventory mapping for in-app traffic. (#4636) --- adapters/ogury/ogury.go | 21 ++-- .../exemplary/app_banner_publisher.json | 97 +++++++++++++++++++ .../app_banner_invalid_request.json | 7 +- .../site_banner_invalid_request.json | 2 +- 4 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 adapters/ogury/ogurytest/exemplary/app_banner_publisher.json diff --git a/adapters/ogury/ogury.go b/adapters/ogury/ogury.go index 7207ff2ac9..1b2293c1bc 100644 --- a/adapters/ogury/ogury.go +++ b/adapters/ogury/ogury.go @@ -87,15 +87,10 @@ func (a adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapter } if len(impsWithOguryParams) == 0 { - if request.Site != nil && (request.Site.Publisher == nil || request.Site.Publisher.ID == "") { + if !hasPublisherId(request) { // we can serve ads with publisherId+adunitcode combination return nil, []error{&errortypes.BadInput{ - Message: "Invalid request. assetKey/adUnitId or request.site.publisher.id required", - }} - } else if request.App != nil { - // for app request there is no adunitcode equivalent so we can't serve ads with just the publisher id - return nil, []error{&errortypes.BadInput{ - Message: "Invalid request. assetKey/adUnitId required", + Message: "Invalid request. assetKey/adUnitId or request.site/app.publisher.id required", }} } } else if len(impsWithOguryParams) > 0 { @@ -149,6 +144,18 @@ func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { } } +func hasPublisherId(request *openrtb2.BidRequest) bool { + return hasSitePublisherId(request) || hasAppPublisherId(request) +} + +func hasSitePublisherId(request *openrtb2.BidRequest) bool { + return request.Site != nil && request.Site.Publisher != nil && request.Site.Publisher.ID != "" +} + +func hasAppPublisherId(request *openrtb2.BidRequest) bool { + return request.App != nil && request.App.Publisher != nil && request.App.Publisher.ID != "" +} + func (a adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { if adapters.IsResponseStatusCodeNoContent(responseData) { return nil, nil diff --git a/adapters/ogury/ogurytest/exemplary/app_banner_publisher.json b/adapters/ogury/ogurytest/exemplary/app_banner_publisher.json new file mode 100644 index 0000000000..6a19c07729 --- /dev/null +++ b/adapters/ogury/ogurytest/exemplary/app_banner_publisher.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "id": "1", + "bundle": "com.example", + "publisher": { + "id": "pub-id" + } + }, + "imp": [ + { + "id": "imp-id", + "banner": { + "format": [{"w": 320, "h": 50}] + }, + "ext": { + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ogury.example.com", + "body": { + "app": { + "id": "1", + "bundle": "com.example", + "publisher": { + "id": "pub-id" + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"imp-id", + "tagid": "imp-id", + "banner": { + "format": [{"w": 320, "h": 50}] + }, + "ext": { + } + } + ] + }, + "impIDs":["imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "seat", + "bid": [{ + "id": "some-UUID", + "impid": "imp-id", + "price": 0.500000, + "nurl": "example nurl", + "adm": "adm string", + "crid": "crid_10", + "h": 100, + "w": 128, + "mtype": 1 + }] + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-UUID", + "impid": "imp-id", + "price": 0.5, + "nurl": "example nurl", + "adm": "adm string", + "crid": "crid_10", + "h": 100, + "w": 128, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/ogury/ogurytest/supplemental/app_banner_invalid_request.json b/adapters/ogury/ogurytest/supplemental/app_banner_invalid_request.json index 36f7948bc1..274258f9fa 100644 --- a/adapters/ogury/ogurytest/supplemental/app_banner_invalid_request.json +++ b/adapters/ogury/ogurytest/supplemental/app_banner_invalid_request.json @@ -3,10 +3,7 @@ "id": "test-request-id", "app": { "id": "1", - "bundle": "com.example", - "publisher": { - "id": "pub-id" - } + "bundle": "com.example" }, "imp": [ { @@ -26,7 +23,7 @@ "expectedBidResponses": [], "expectedMakeRequestsErrors": [{ - "value": "Invalid request. assetKey/adUnitId required", + "value": "Invalid request. assetKey/adUnitId or request.site/app.publisher.id required", "comparison": "literal" }] } diff --git a/adapters/ogury/ogurytest/supplemental/site_banner_invalid_request.json b/adapters/ogury/ogurytest/supplemental/site_banner_invalid_request.json index e26875ba07..c385c9f1e6 100644 --- a/adapters/ogury/ogurytest/supplemental/site_banner_invalid_request.json +++ b/adapters/ogury/ogurytest/supplemental/site_banner_invalid_request.json @@ -22,7 +22,7 @@ "httpCalls": [], "expectedBidResponses": [], "expectedMakeRequestsErrors": [{ - "value": "Invalid request. assetKey/adUnitId or request.site.publisher.id required", + "value": "Invalid request. assetKey/adUnitId or request.site/app.publisher.id required", "comparison": "literal" }] } From 6395368ca643546b4c4a73fa6925b19d00348e40 Mon Sep 17 00:00:00 2001 From: dxtech-git <github@dxtech.ai> Date: Fri, 30 Jan 2026 23:42:37 +0200 Subject: [PATCH 153/272] DXKulture: Remove Adapter (#4653) --- adapters/dxkulture/dxkulture.go | 172 ------------------ adapters/dxkulture/dxkulture_test.go | 17 -- .../dxkulturetest/exemplary/banner.json | 145 --------------- .../exemplary/empty-site-domain-ref.json | 143 --------------- .../dxkulturetest/exemplary/ipv6.json | 143 --------------- .../exemplary/video-test-request.json | 155 ---------------- .../dxkulturetest/exemplary/video.json | 153 ---------------- .../supplemental/invalid-imp-ext-bidder.json | 40 ---- .../supplemental/invalid-imp-ext.json | 38 ---- .../supplemental/invalid-response.json | 114 ------------ .../dxkulturetest/supplemental/no-mtype.json | 143 --------------- .../supplemental/status-code-bad-request.json | 113 ------------ .../supplemental/status-code-no-content.json | 109 ----------- .../supplemental/status-code-other-error.json | 113 ------------ adapters/dxkulture/params_test.go | 53 ------ exchange/adapter_builders.go | 2 - openrtb_ext/bidders.go | 2 - openrtb_ext/imp_dxkulture.go | 7 - static/bidder-info/dxkulture.yaml | 16 -- static/bidder-params/dxkulture.json | 20 -- 20 files changed, 1698 deletions(-) delete mode 100644 adapters/dxkulture/dxkulture.go delete mode 100644 adapters/dxkulture/dxkulture_test.go delete mode 100644 adapters/dxkulture/dxkulturetest/exemplary/banner.json delete mode 100644 adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json delete mode 100644 adapters/dxkulture/dxkulturetest/exemplary/ipv6.json delete mode 100644 adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json delete mode 100644 adapters/dxkulture/dxkulturetest/exemplary/video.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json delete mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json delete mode 100644 adapters/dxkulture/params_test.go delete mode 100644 openrtb_ext/imp_dxkulture.go delete mode 100644 static/bidder-info/dxkulture.yaml delete mode 100644 static/bidder-params/dxkulture.json diff --git a/adapters/dxkulture/dxkulture.go b/adapters/dxkulture/dxkulture.go deleted file mode 100644 index 6b4bfa4003..0000000000 --- a/adapters/dxkulture/dxkulture.go +++ /dev/null @@ -1,172 +0,0 @@ -package dxkulture - -import ( - "encoding/json" - "fmt" - "net/http" - "net/url" - - "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" - - "github.com/prebid/openrtb/v20/openrtb2" -) - -var markupTypeToBidType = map[openrtb2.MarkupType]openrtb_ext.BidType{ - openrtb2.MarkupBanner: openrtb_ext.BidTypeBanner, - openrtb2.MarkupVideo: openrtb_ext.BidTypeVideo, -} - -type adapter struct { - endpoint string -} - -// Builder builds a new instance of the DXKulture adapter for the given bidder with the given config. -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) { - impressions := request.Imp - - adapterRequests := make([]*adapters.RequestData, 0, len(impressions)) - var errs []error - - for _, impression := range impressions { - impExt, err := parseExt(&impression) - if err != nil { - errs = append(errs, err) - continue - } - - request.Imp = []openrtb2.Imp{impression} - body, err := json.Marshal(request) - if err != nil { - errs = append(errs, err) - continue - } - - if request.Test == 1 { - impExt.PublisherId = "test" - } - - params := url.Values{} - params.Add("publisher_id", impExt.PublisherId) - params.Add("placement_id", impExt.PlacementId) - - adapterRequests = append(adapterRequests, &adapters.RequestData{ - Method: http.MethodPost, - Uri: a.endpoint + "?" + params.Encode(), - Body: body, - Headers: getHeaders(request), - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - }) - } - - request.Imp = impressions - return adapterRequests, errs -} - -func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if adapters.IsResponseStatusCodeNoContent(response) { - return nil, nil - } - if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { - return nil, []error{err} - } - - var ortbResponse openrtb2.BidResponse - err := jsonutil.Unmarshal(response.Body, &ortbResponse) - if err != nil { - return nil, []error{&errortypes.BadServerResponse{ - Message: "Bad Server Response", - }} - } - - var bidErrors []error - - bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1) - for _, seatBid := range ortbResponse.SeatBid { - for i := range seatBid.Bid { - bid := seatBid.Bid[i] - bidType, err := getBidType(&bid) - if err != nil { - bidErrors = append(bidErrors, err) - continue - } - - bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ - Bid: &bid, - BidType: bidType, - }) - } - } - - return bidderResponse, bidErrors -} - -func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { - if bidType, ok := markupTypeToBidType[bid.MType]; ok { - return bidType, nil - } - return "", &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Unsupported MType %d", bid.MType), - } -} - -func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpDXKulture, error) { - var bidderExt adapters.ExtImpBidder - - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - return nil, &errortypes.BadInput{ - Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err), - } - } - - impExt := openrtb_ext.ExtImpDXKulture{} - err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt) - if err != nil { - return nil, &errortypes.BadInput{ - Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err), - } - } - - return &impExt, nil -} - -func getHeaders(request *openrtb2.BidRequest) http.Header { - headers := http.Header{} - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - headers.Add("X-Openrtb-Version", "2.5") - - if request.Site != nil { - if request.Site.Ref != "" { - headers.Set("Referer", request.Site.Ref) - } - if request.Site.Domain != "" { - headers.Add("Origin", request.Site.Domain) - } - } - - if request.Device != nil { - if len(request.Device.UA) > 0 { - headers.Add("User-Agent", request.Device.UA) - } - - if len(request.Device.IPv6) > 0 { - headers.Add("X-Forwarded-For", request.Device.IPv6) - } - - if len(request.Device.IP) > 0 { - headers.Add("X-Forwarded-For", request.Device.IP) - } - } - return headers -} diff --git a/adapters/dxkulture/dxkulture_test.go b/adapters/dxkulture/dxkulture_test.go deleted file mode 100644 index 2ee176968b..0000000000 --- a/adapters/dxkulture/dxkulture_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package dxkulture - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/config" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder("dxkulture", config.Adapter{Endpoint: "https://ads.dxkulture.com/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - adapterstest.RunJSONBidderTest(t, "dxkulturetest", bidder) -} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/banner.json b/adapters/dxkulture/dxkulturetest/exemplary/banner.json deleted file mode 100644 index 6ae690bece..0000000000 --- a/adapters/dxkulture/dxkulturetest/exemplary/banner.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<iframe width=\"300\" height=\"250\"></iframe>", - "mtype": 1 - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<iframe width=\"300\" height=\"250\"></iframe>", - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json b/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json deleted file mode 100644 index 8c2408b291..0000000000 --- a/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "page": "http://site.com/page" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "page": "http://site.com/page" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json b/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json deleted file mode 100644 index ca23591b92..0000000000 --- a/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "page": "http://site.com/page" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "2001:0000:130F:0000:0000:09C0:876A:130B" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "page": "http://site.com/page" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json b/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json deleted file mode 100644 index 2b3599f942..0000000000 --- a/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "test": 1, - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=test", - "body": { - "id": "test-request-id", - "test": 1, - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/video.json b/adapters/dxkulture/dxkulturetest/exemplary/video.json deleted file mode 100644 index b96fb107e3..0000000000 --- a/adapters/dxkulture/dxkulturetest/exemplary/video.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>", - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json deleted file mode 100644 index c60c608057..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": "not_json" - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "expectedMakeRequestsErrors": [ - { - "value": "Ignoring imp id=test-imp-id, error while decoding impExt, err: expect { or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json deleted file mode 100644 index 379acd586c..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": "not_json" - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "expectedMakeRequestsErrors": [ - { - "value": "Ignoring imp id=test-imp-id, error while decoding extImpBidder, err: expect { or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json deleted file mode 100644 index 40d18e6343..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": "body" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Bad Server Response", - "comparison": "literal" - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json b/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json deleted file mode 100644 index fe0f8a1202..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "cur": "USD", - "seatbid": [ - { - "bid": [ - { - "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", - "crid": "16329", - "adomain": [ - "adomain.com" - ], - "price": 3, - "impid": "test-imp-id", - "adid": "2422", - "adm": "<?xml version=\"1.0\"?><VAST version=\"3.0\"></VAST>" - } - ], - "seat": "dxkulture" - } - ], - "bidid": "test-request-id", - "id": "test-request-id" - } - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unsupported MType 0", - "comparison": "literal" - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [] - } - ] - -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json deleted file mode 100644 index f152bb9ecf..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 400 - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json deleted file mode 100644 index 75bae07d4f..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 204 - } - } - ], - "expectedBidResponses": [], - "expectedMakeBidsErrors": [] -} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json deleted file mode 100644 index a568c3910b..0000000000 --- a/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "httpCalls": [ - { - "expectedRequest": { - "method": "GET", - "headers": { - "Referer": [ - "http://site.com/ref" - ], - "Origin": [ - "site.com" - ], - "Accept": [ - "application/json" - ], - "Content-Type": [ - "application/json;charset=utf-8" - ], - "User-Agent": [ - "user-agent" - ], - "X-Forwarded-For": [ - "1.2.3.4" - ], - "X-Openrtb-Version": [ - "2.5" - ] - }, - "uri": "https://ads.dxkulture.com/pbs?placement_id=placement123&publisher_id=pub123", - "body": { - "id": "test-request-id", - "user": { - "buyeruid": "userId", - "yob": 1990 - }, - "device": { - "ua": "user-agent", - "ip": "1.2.3.4" - }, - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 1920, - "h": 1080, - "mimes": [ - "video/x-flv", - "video/mp4" - ] - }, - "ext": { - "bidder": { - "publisherId": "pub123", - "placementId": "placement123" - } - } - } - ], - "site": { - "domain": "site.com", - "page": "http://site.com/page", - "ref": "http://site.com/ref" - } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 505 - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 505. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} diff --git a/adapters/dxkulture/params_test.go b/adapters/dxkulture/params_test.go deleted file mode 100644 index c7997f1862..0000000000 --- a/adapters/dxkulture/params_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package dxkulture - -import ( - "encoding/json" - "testing" - - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -// This file actually intends to test static/bidder-params/dxkulture.json -// -// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxkulture - -// TestValidParams makes sure that the dxkulture schema accepts all imp.ext fields which we intend to support. -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.BidderDXKulture, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected dxkulture params: %s", validParam) - } - } -} - -// TestInvalidParams makes sure that the dxkulture schema rejects all the imp.ext fields we don't support. -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.BidderDXKulture, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } - } -} - -var validParams = []string{ - `{"publisherId": "pub", "placementId": "plac"}`, - `{"publisherId": "pub", "placementId": "plac", "a":1}`, -} - -var invalidParams = []string{ - `{"publisherId": "pub"}`, - `{"placementId": "plac"}`, - //malformed - `{"ub", "placementId": "plac"}`, - `{}`, -} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 3cb651bcbd..325833ef71 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -96,7 +96,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/displayio" "github.com/prebid/prebid-server/v3/adapters/dmx" "github.com/prebid/prebid-server/v3/adapters/driftpixel" - "github.com/prebid/prebid-server/v3/adapters/dxkulture" evolution "github.com/prebid/prebid-server/v3/adapters/e_volution" "github.com/prebid/prebid-server/v3/adapters/edge226" "github.com/prebid/prebid-server/v3/adapters/emtv" @@ -363,7 +362,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderDisplayio: displayio.Builder, openrtb_ext.BidderEdge226: edge226.Builder, openrtb_ext.BidderDmx: dmx.Builder, - openrtb_ext.BidderDXKulture: dxkulture.Builder, openrtb_ext.BidderDriftPixel: driftpixel.Builder, openrtb_ext.BidderEmtv: emtv.Builder, openrtb_ext.BidderEmxDigital: cadentaperturemx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index e94d0fe551..1d2f9f108c 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -112,7 +112,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderDisplayio, BidderEdge226, BidderDmx, - BidderDXKulture, BidderDriftPixel, BidderEmtv, BidderEmxDigital, @@ -486,7 +485,6 @@ const ( BidderDisplayio BidderName = "displayio" BidderEdge226 BidderName = "edge226" BidderDmx BidderName = "dmx" - BidderDXKulture BidderName = "dxkulture" BidderDriftPixel BidderName = "driftpixel" BidderEmtv BidderName = "emtv" BidderEmxDigital BidderName = "emx_digital" diff --git a/openrtb_ext/imp_dxkulture.go b/openrtb_ext/imp_dxkulture.go deleted file mode 100644 index 4b507c5524..0000000000 --- a/openrtb_ext/imp_dxkulture.go +++ /dev/null @@ -1,7 +0,0 @@ -package openrtb_ext - -// ExtImpDXKulture defines the contract for bidrequest.imp[i].ext.prebid.bidder.dxkulture -type ExtImpDXKulture struct { - PublisherId string `json:"publisherId"` - PlacementId string `json:"placementId"` -} diff --git a/static/bidder-info/dxkulture.yaml b/static/bidder-info/dxkulture.yaml deleted file mode 100644 index d6f03044fd..0000000000 --- a/static/bidder-info/dxkulture.yaml +++ /dev/null @@ -1,16 +0,0 @@ -endpoint: "https://ads.dxkulture.com/pbs" -maintainer: - email: "devops@dxkulture.com" -capabilities: - app: - mediaTypes: - - banner - - video - site: - mediaTypes: - - banner - - video -userSync: - redirect: - url: "https://ads.dxkulture.com/usync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb={{.RedirectURL}}" - userMacro: "$UID" diff --git a/static/bidder-params/dxkulture.json b/static/bidder-params/dxkulture.json deleted file mode 100644 index 858eefd22e..0000000000 --- a/static/bidder-params/dxkulture.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "DXKulture Adapter Params", - "description": "A schema which validates params accepted by the DXKulture adapter", - "type": "object", - "properties": { - "publisherId": { - "type": "string", - "description": "The publisher id" - }, - "placementId": { - "type": "string", - "description": "The placement id" - } - }, - "required": [ - "publisherId", - "placementId" - ] -} From 50810480e9ef1b265ea670cb490416eaa5b8d345 Mon Sep 17 00:00:00 2001 From: Anna Yablonsky <annay@perion.com> Date: Mon, 2 Feb 2026 17:33:54 +0200 Subject: [PATCH 154/272] New Adapter: ProgrammaticX - Vidazoo Alias (#4456) --- static/bidder-info/programmaticX.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/programmaticX.yaml diff --git a/static/bidder-info/programmaticX.yaml b/static/bidder-info/programmaticX.yaml new file mode 100644 index 0000000000..0e203e8e46 --- /dev/null +++ b/static/bidder-info/programmaticX.yaml @@ -0,0 +1,9 @@ +aliasOf: "vidazoo" +endpoint: "https://exchange.programmaticx.ai/openrtb/" +maintainer: + email: "pxteam@programmaticx.ai" +gvlVendorID: 1344 +userSync: + iframe: + url: https://sync.programmaticx.ai/api/user/html/685297194d85991a5e6e36dd?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} \ No newline at end of file From 8619d9f5cac46ca680bcffbf854783f80b031d12 Mon Sep 17 00:00:00 2001 From: support-gotham-ads <support@gothamads.com> Date: Tue, 3 Feb 2026 16:39:37 +0200 Subject: [PATCH 155/272] Gothamads: Rename to intenze (#4333) --- .../{gothamads/gothamads.go => intenze/intenze.go} | 12 ++++++------ .../gothamads_test.go => intenze/intenze_test.go} | 10 +++++----- .../intenzetest}/exemplary/banner-app.json | 8 +++++--- .../intenzetest}/exemplary/banner-web.json | 9 ++++++--- .../intenzetest}/exemplary/native-app.json | 8 +++++--- .../intenzetest}/exemplary/native-web.json | 8 +++++--- .../intenzetest}/exemplary/video-app.json | 8 +++++--- .../intenzetest}/exemplary/video-web.json | 8 +++++--- .../intenzetest}/supplemental/bad_media_type.json | 8 +++++--- .../supplemental/empty-seatbid-array.json | 6 ++++-- .../supplemental/invalid-bidder-ext-object.json | 0 .../supplemental/invalid-intenze-ext-object.json} | 0 .../supplemental/invalid-response.json | 6 ++++-- .../supplemental/status-code-bad-request.json | 6 ++++-- .../supplemental/status-code-no-content.json | 6 ++++-- .../supplemental/status-code-other-error.json | 6 ++++-- .../status-code-service-unavailable.json | 6 ++++-- adapters/{gothamads => intenze}/params_test.go | 8 ++++---- exchange/adapter_builders.go | 4 ++-- exchange/adapter_util.go | 1 + openrtb_ext/bidders.go | 4 ++-- openrtb_ext/{imp_gothamads.go => imp_intenze.go} | 2 +- static/bidder-info/gothamads.yaml | 14 -------------- static/bidder-info/intenze.yaml | 14 ++++++++++++-- .../bidder-params/{gothamads.json => intenze.json} | 4 ++-- 25 files changed, 95 insertions(+), 71 deletions(-) rename adapters/{gothamads/gothamads.go => intenze/intenze.go} (92%) rename adapters/{gothamads/gothamads_test.go => intenze/intenze_test.go} (59%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/banner-app.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/banner-web.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/native-app.json (96%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/native-web.json (96%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/video-app.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/exemplary/video-web.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/bad_media_type.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/empty-seatbid-array.json (95%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/invalid-bidder-ext-object.json (100%) rename adapters/{gothamads/gothamadstest/supplemental/invalid-gotham-ext-object.json => intenze/intenzetest/supplemental/invalid-intenze-ext-object.json} (100%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/invalid-response.json (94%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/status-code-bad-request.json (94%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/status-code-no-content.json (92%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/status-code-other-error.json (93%) rename adapters/{gothamads/gothamadstest => intenze/intenzetest}/supplemental/status-code-service-unavailable.json (92%) rename adapters/{gothamads => intenze}/params_test.go (75%) rename openrtb_ext/{imp_gothamads.go => imp_intenze.go} (68%) delete mode 100644 static/bidder-info/gothamads.yaml rename static/bidder-params/{gothamads.json => intenze.json} (84%) diff --git a/adapters/gothamads/gothamads.go b/adapters/intenze/intenze.go similarity index 92% rename from adapters/gothamads/gothamads.go rename to adapters/intenze/intenze.go index 7b2f247108..6a1994ea12 100644 --- a/adapters/gothamads/gothamads.go +++ b/adapters/intenze/intenze.go @@ -1,4 +1,4 @@ -package gothamads +package intenze import ( "encoding/json" @@ -81,24 +81,24 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, reqInfo *ada }}, nil } -func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtGothamAds, error) { +func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtIntenze, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { return nil, &errortypes.BadInput{ Message: err.Error(), } } - var gothamadsExt openrtb_ext.ExtGothamAds - if err := jsonutil.Unmarshal(bidderExt.Bidder, &gothamadsExt); err != nil { + var intenzeExt openrtb_ext.ExtIntenze + if err := jsonutil.Unmarshal(bidderExt.Bidder, &intenzeExt); err != nil { return nil, &errortypes.BadInput{ Message: err.Error(), } } - return &gothamadsExt, nil + return &intenzeExt, nil } -func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtGothamAds) (string, error) { +func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtIntenze) (string, error) { endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID} return macros.ResolveMacros(a.endpoint, endpointParams) } diff --git a/adapters/gothamads/gothamads_test.go b/adapters/intenze/intenze_test.go similarity index 59% rename from adapters/gothamads/gothamads_test.go rename to adapters/intenze/intenze_test.go index b3433ae44a..3ea1247ad5 100644 --- a/adapters/gothamads/gothamads_test.go +++ b/adapters/intenze/intenze_test.go @@ -1,4 +1,4 @@ -package gothamads +package intenze import ( "testing" @@ -10,18 +10,18 @@ import ( ) func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderGothamads, config.Adapter{ - Endpoint: "http://us-e-node1.gothamads.com/?pass={{.AccountID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + bidder, buildErr := Builder(openrtb_ext.BidderIntenze, config.Adapter{ + Endpoint: "http://lb-east.intenze.co/?pass={{.AccountID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) } - adapterstest.RunJSONBidderTest(t, "gothamadstest", bidder) + adapterstest.RunJSONBidderTest(t, "intenzetest", bidder) } func TestEndpointTemplateMalformed(t *testing.T) { - _, buildErr := Builder(openrtb_ext.BidderGothamads, config.Adapter{ + _, buildErr := Builder(openrtb_ext.BidderIntenze, config.Adapter{ Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) assert.Error(t, buildErr) diff --git a/adapters/gothamads/gothamadstest/exemplary/banner-app.json b/adapters/intenze/intenzetest/exemplary/banner-app.json similarity index 95% rename from adapters/gothamads/gothamadstest/exemplary/banner-app.json rename to adapters/intenze/intenzetest/exemplary/banner-app.json index 61fd85abc7..1b80ff5bf0 100644 --- a/adapters/gothamads/gothamadstest/exemplary/banner-app.json +++ b/adapters/intenze/intenzetest/exemplary/banner-app.json @@ -59,7 +59,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -95,7 +95,9 @@ }, "tmax": 1000 }, - "impIDs":["1"] + "impIDs": [ + "1" + ] }, "mockResponse": { "status": 200, @@ -119,7 +121,7 @@ } ], "type": "banner", - "seat": "gothamAds" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/exemplary/banner-web.json b/adapters/intenze/intenzetest/exemplary/banner-web.json similarity index 95% rename from adapters/gothamads/gothamadstest/exemplary/banner-web.json rename to adapters/intenze/intenzetest/exemplary/banner-web.json index 0d09bbeb1f..825ee9c72c 100644 --- a/adapters/gothamads/gothamadstest/exemplary/banner-web.json +++ b/adapters/intenze/intenzetest/exemplary/banner-web.json @@ -66,7 +66,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -109,7 +109,10 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id1","some-impression-id2"] + "impIDs": [ + "some-impression-id1", + "some-impression-id2" + ] }, "mockResponse": { "status": 200, @@ -146,7 +149,7 @@ } ], "type": "banner", - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/exemplary/native-app.json b/adapters/intenze/intenzetest/exemplary/native-app.json similarity index 96% rename from adapters/gothamads/gothamadstest/exemplary/native-app.json rename to adapters/intenze/intenzetest/exemplary/native-app.json index 16ba08b5eb..57bc6dd727 100644 --- a/adapters/gothamads/gothamadstest/exemplary/native-app.json +++ b/adapters/intenze/intenzetest/exemplary/native-app.json @@ -59,7 +59,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -95,7 +95,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, @@ -117,7 +119,7 @@ } ], "type": "native", - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/exemplary/native-web.json b/adapters/intenze/intenzetest/exemplary/native-web.json similarity index 96% rename from adapters/gothamads/gothamadstest/exemplary/native-web.json rename to adapters/intenze/intenzetest/exemplary/native-web.json index 943871a008..31dedc4403 100644 --- a/adapters/gothamads/gothamadstest/exemplary/native-web.json +++ b/adapters/intenze/intenzetest/exemplary/native-web.json @@ -53,7 +53,7 @@ "2607:fb90:f27:4512:d800:cb23:a603:e245" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -83,7 +83,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, @@ -104,7 +106,7 @@ "mtype": 4 } ], - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/exemplary/video-app.json b/adapters/intenze/intenzetest/exemplary/video-app.json similarity index 95% rename from adapters/gothamads/gothamadstest/exemplary/video-app.json rename to adapters/intenze/intenzetest/exemplary/video-app.json index ce2e289014..dd836ee34c 100644 --- a/adapters/gothamads/gothamadstest/exemplary/video-app.json +++ b/adapters/intenze/intenzetest/exemplary/video-app.json @@ -64,7 +64,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -105,7 +105,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, @@ -128,7 +130,7 @@ "mtype": 2 } ], - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/exemplary/video-web.json b/adapters/intenze/intenzetest/exemplary/video-web.json similarity index 95% rename from adapters/gothamads/gothamadstest/exemplary/video-web.json rename to adapters/intenze/intenzetest/exemplary/video-web.json index a475fc5a0c..c8b596f06a 100644 --- a/adapters/gothamads/gothamadstest/exemplary/video-web.json +++ b/adapters/intenze/intenzetest/exemplary/video-web.json @@ -58,7 +58,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -93,7 +93,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, @@ -121,7 +123,7 @@ "mtype": 2 } ], - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/supplemental/bad_media_type.json b/adapters/intenze/intenzetest/supplemental/bad_media_type.json similarity index 95% rename from adapters/gothamads/gothamadstest/supplemental/bad_media_type.json rename to adapters/intenze/intenzetest/supplemental/bad_media_type.json index 0079ce3e71..6b8050c0e7 100644 --- a/adapters/gothamads/gothamadstest/supplemental/bad_media_type.json +++ b/adapters/intenze/intenzetest/supplemental/bad_media_type.json @@ -59,7 +59,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -95,7 +95,9 @@ }, "tmax": 1000 }, - "impIDs":["1"] + "impIDs": [ + "1" + ] }, "mockResponse": { "status": 200, @@ -118,7 +120,7 @@ } ], "mtype": 0, - "seat": "gothamads" + "seat": "intenze" } ], "cur": "USD" diff --git a/adapters/gothamads/gothamadstest/supplemental/empty-seatbid-array.json b/adapters/intenze/intenzetest/supplemental/empty-seatbid-array.json similarity index 95% rename from adapters/gothamads/gothamadstest/supplemental/empty-seatbid-array.json rename to adapters/intenze/intenzetest/supplemental/empty-seatbid-array.json index 58970bd8e8..3302320c06 100644 --- a/adapters/gothamads/gothamadstest/supplemental/empty-seatbid-array.json +++ b/adapters/intenze/intenzetest/supplemental/empty-seatbid-array.json @@ -64,7 +64,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -105,7 +105,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, diff --git a/adapters/gothamads/gothamadstest/supplemental/invalid-bidder-ext-object.json b/adapters/intenze/intenzetest/supplemental/invalid-bidder-ext-object.json similarity index 100% rename from adapters/gothamads/gothamadstest/supplemental/invalid-bidder-ext-object.json rename to adapters/intenze/intenzetest/supplemental/invalid-bidder-ext-object.json diff --git a/adapters/gothamads/gothamadstest/supplemental/invalid-gotham-ext-object.json b/adapters/intenze/intenzetest/supplemental/invalid-intenze-ext-object.json similarity index 100% rename from adapters/gothamads/gothamadstest/supplemental/invalid-gotham-ext-object.json rename to adapters/intenze/intenzetest/supplemental/invalid-intenze-ext-object.json diff --git a/adapters/gothamads/gothamadstest/supplemental/invalid-response.json b/adapters/intenze/intenzetest/supplemental/invalid-response.json similarity index 94% rename from adapters/gothamads/gothamadstest/supplemental/invalid-response.json rename to adapters/intenze/intenzetest/supplemental/invalid-response.json index fe9cb3fd38..585ea65963 100644 --- a/adapters/gothamads/gothamadstest/supplemental/invalid-response.json +++ b/adapters/intenze/intenzetest/supplemental/invalid-response.json @@ -59,7 +59,7 @@ "123.123.123.123" ] }, - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "device": { @@ -95,7 +95,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 200, diff --git a/adapters/gothamads/gothamadstest/supplemental/status-code-bad-request.json b/adapters/intenze/intenzetest/supplemental/status-code-bad-request.json similarity index 94% rename from adapters/gothamads/gothamadstest/supplemental/status-code-bad-request.json rename to adapters/intenze/intenzetest/supplemental/status-code-bad-request.json index b0e2a09855..746a56355b 100644 --- a/adapters/gothamads/gothamadstest/supplemental/status-code-bad-request.json +++ b/adapters/intenze/intenzetest/supplemental/status-code-bad-request.json @@ -41,7 +41,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "imp": [ @@ -76,7 +76,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 400 diff --git a/adapters/gothamads/gothamadstest/supplemental/status-code-no-content.json b/adapters/intenze/intenzetest/supplemental/status-code-no-content.json similarity index 92% rename from adapters/gothamads/gothamadstest/supplemental/status-code-no-content.json rename to adapters/intenze/intenzetest/supplemental/status-code-no-content.json index 97fbc419af..ad8a50ccc1 100644 --- a/adapters/gothamads/gothamadstest/supplemental/status-code-no-content.json +++ b/adapters/intenze/intenzetest/supplemental/status-code-no-content.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "imp": [ @@ -64,7 +64,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 204 diff --git a/adapters/gothamads/gothamadstest/supplemental/status-code-other-error.json b/adapters/intenze/intenzetest/supplemental/status-code-other-error.json similarity index 93% rename from adapters/gothamads/gothamadstest/supplemental/status-code-other-error.json rename to adapters/intenze/intenzetest/supplemental/status-code-other-error.json index 5d1916cce7..59ef26aa88 100644 --- a/adapters/gothamads/gothamadstest/supplemental/status-code-other-error.json +++ b/adapters/intenze/intenzetest/supplemental/status-code-other-error.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "imp": [ @@ -64,7 +64,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 306 diff --git a/adapters/gothamads/gothamadstest/supplemental/status-code-service-unavailable.json b/adapters/intenze/intenzetest/supplemental/status-code-service-unavailable.json similarity index 92% rename from adapters/gothamads/gothamadstest/supplemental/status-code-service-unavailable.json rename to adapters/intenze/intenzetest/supplemental/status-code-service-unavailable.json index e69644e967..138865eefb 100644 --- a/adapters/gothamads/gothamadstest/supplemental/status-code-service-unavailable.json +++ b/adapters/intenze/intenzetest/supplemental/status-code-service-unavailable.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://us-e-node1.gothamads.com/?pass=accountId", + "uri": "http://lb-east.intenze.co/?pass=accountId", "body": { "id": "some-request-id", "imp": [ @@ -64,7 +64,9 @@ }, "tmax": 1000 }, - "impIDs":["some-impression-id"] + "impIDs": [ + "some-impression-id" + ] }, "mockResponse": { "status": 503 diff --git a/adapters/gothamads/params_test.go b/adapters/intenze/params_test.go similarity index 75% rename from adapters/gothamads/params_test.go rename to adapters/intenze/params_test.go index ff61796deb..2e2b66ef74 100644 --- a/adapters/gothamads/params_test.go +++ b/adapters/intenze/params_test.go @@ -1,4 +1,4 @@ -package gothamads +package intenze import ( "encoding/json" @@ -18,8 +18,8 @@ func TestValidParams(t *testing.T) { } for _, validParam := range validParams { - if err := validator.Validate(openrtb_ext.BidderGothamads, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected Gothamads params: %s", validParam) + if err := validator.Validate(openrtb_ext.BidderIntenze, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Intenze params: %s", validParam) } } } @@ -43,7 +43,7 @@ func TestInvalidParams(t *testing.T) { } for _, invalidParam := range invalidParams { - if err := validator.Validate(openrtb_ext.BidderGothamads, json.RawMessage(invalidParam)); err == nil { + if err := validator.Validate(openrtb_ext.BidderIntenze, json.RawMessage(invalidParam)); err == nil { t.Errorf("Schema allowed unexpected params: %s", invalidParam) } } diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 325833ef71..0c81a92e0d 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -113,7 +113,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/gamoshi" "github.com/prebid/prebid-server/v3/adapters/globalsun" "github.com/prebid/prebid-server/v3/adapters/goldbach" - "github.com/prebid/prebid-server/v3/adapters/gothamads" "github.com/prebid/prebid-server/v3/adapters/grid" "github.com/prebid/prebid-server/v3/adapters/gumgum" "github.com/prebid/prebid-server/v3/adapters/huaweiads" @@ -123,6 +122,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/infytv" "github.com/prebid/prebid-server/v3/adapters/inmobi" "github.com/prebid/prebid-server/v3/adapters/insticator" + "github.com/prebid/prebid-server/v3/adapters/intenze" "github.com/prebid/prebid-server/v3/adapters/interactiveoffers" "github.com/prebid/prebid-server/v3/adapters/intertech" "github.com/prebid/prebid-server/v3/adapters/invibes" @@ -380,7 +380,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderGamoshi: gamoshi.Builder, openrtb_ext.BidderGlobalsun: globalsun.Builder, openrtb_ext.BidderGoldbach: goldbach.Builder, - openrtb_ext.BidderGothamads: gothamads.Builder, openrtb_ext.BidderGrid: grid.Builder, openrtb_ext.BidderGumGum: gumgum.Builder, openrtb_ext.BidderHuaweiAds: huaweiads.Builder, @@ -390,6 +389,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderInfyTV: infytv.Builder, openrtb_ext.BidderInMobi: inmobi.Builder, openrtb_ext.BidderInsticator: insticator.Builder, + openrtb_ext.BidderIntenze: intenze.Builder, openrtb_ext.BidderInteractiveoffers: interactiveoffers.Builder, openrtb_ext.BidderIntertech: intertech.Builder, openrtb_ext.BidderInvibes: invibes.Builder, diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index b221a1adfb..27e36a0705 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -126,6 +126,7 @@ func GetDisabledBidderWarningMessages(infos config.BidderInfos) map[string]strin "nanointeractive": `Bidder "nanointeractive" is no longer available in Prebid Server. Please update your configuration.`, "bizzclick": `Bidder "bizzclick" is no longer available in Prebid Server. Please update your configuration. "bizzclick" has been renamed to "blasto".`, "liftoff": `Bidder "liftoff" is no longer available in Prebid Server. If you're looking to use the Vungle Exchange adapter, please rename it to "vungle" in your configuration.`, + "gothamads": `Bidder "gothamads" is no longer available in Prebid Server. Please rename it to "intenze" in your configuration.`, } return mergeRemovedAndDisabledBidderWarningMessages(removed, infos) diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1d2f9f108c..91a71c3ecf 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -130,7 +130,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderGamoshi, BidderGlobalsun, BidderGoldbach, - BidderGothamads, BidderGrid, BidderGumGum, BidderHuaweiAds, @@ -140,6 +139,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderInfyTV, BidderInMobi, BidderInsticator, + BidderIntenze, BidderInteractiveoffers, BidderIntertech, BidderInvibes, @@ -503,7 +503,6 @@ const ( BidderGamoshi BidderName = "gamoshi" BidderGlobalsun BidderName = "globalsun" BidderGoldbach BidderName = "goldbach" - BidderGothamads BidderName = "gothamads" BidderGrid BidderName = "grid" BidderGumGum BidderName = "gumgum" BidderHuaweiAds BidderName = "huaweiads" @@ -513,6 +512,7 @@ const ( BidderInfyTV BidderName = "infytv" BidderInMobi BidderName = "inmobi" BidderInsticator BidderName = "insticator" + BidderIntenze BidderName = "intenze" BidderInteractiveoffers BidderName = "interactiveoffers" BidderIntertech BidderName = "intertech" BidderInvibes BidderName = "invibes" diff --git a/openrtb_ext/imp_gothamads.go b/openrtb_ext/imp_intenze.go similarity index 68% rename from openrtb_ext/imp_gothamads.go rename to openrtb_ext/imp_intenze.go index fb945fbba6..991c4817ac 100644 --- a/openrtb_ext/imp_gothamads.go +++ b/openrtb_ext/imp_intenze.go @@ -1,5 +1,5 @@ package openrtb_ext -type ExtGothamAds struct { +type ExtIntenze struct { AccountID string `json:"accountId"` } diff --git a/static/bidder-info/gothamads.yaml b/static/bidder-info/gothamads.yaml deleted file mode 100644 index c9f4e66b48..0000000000 --- a/static/bidder-info/gothamads.yaml +++ /dev/null @@ -1,14 +0,0 @@ -endpoint: "http://us-e-node1.gothamads.com/?pass={{.AccountID}}" -maintainer: - email: "support@gothamads.com" -capabilities: - app: - mediaTypes: - - banner - - video - - native - site: - mediaTypes: - - banner - - video - - native \ No newline at end of file diff --git a/static/bidder-info/intenze.yaml b/static/bidder-info/intenze.yaml index 14eec4d694..fe8d7635ad 100644 --- a/static/bidder-info/intenze.yaml +++ b/static/bidder-info/intenze.yaml @@ -1,4 +1,14 @@ -aliasOf: "gothamads" endpoint: "http://lb-east.intenze.co/?pass={{.AccountID}}" maintainer: - email: "connect@intenze.co" \ No newline at end of file + email: "connect@intenze.co" +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/gothamads.json b/static/bidder-params/intenze.json similarity index 84% rename from static/bidder-params/gothamads.json rename to static/bidder-params/intenze.json index 030d43eb31..1d42a6535f 100644 --- a/static/bidder-params/gothamads.json +++ b/static/bidder-params/intenze.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Gothamads Adapter Params", - "description": "A schema which validates params accepted by the Gothamads adapter", + "title": "Intenze Adapter Params", + "description": "A schema which validates params accepted by the Intenze adapter", "type": "object", "properties": { "accountId": { From 21e01fd3fdb642417a1f50a9fb1605812f8e2386 Mon Sep 17 00:00:00 2001 From: Screencore Developer <connect@screencore.io> Date: Tue, 3 Feb 2026 16:45:43 +0200 Subject: [PATCH 156/272] Screencore: Convert to Teqblaze alias (#4611) --- adapters/screencore/params_test.go | 50 ----- adapters/screencore/screencore.go | 178 ---------------- adapters/screencore/screencore_test.go | 20 -- .../screencoretest/exemplary/banner-app.json | 153 -------------- .../screencoretest/exemplary/banner-web.json | 198 ------------------ .../screencoretest/exemplary/native-app.json | 149 ------------- .../screencoretest/exemplary/native-web.json | 136 ------------ .../screencoretest/exemplary/video-app.json | 162 -------------- .../screencoretest/exemplary/video-web.json | 160 -------------- .../supplemental/bad_media_type.json | 136 ------------ .../supplemental/empty-imp-array.json | 16 -- .../supplemental/empty-seatbid-array.json | 131 ------------ .../invalid-bidder-ext-object.json | 33 --- .../supplemental/invalid-response.json | 113 ---------- .../invalid-screencore-ext-object.json | 31 --- .../supplemental/status-code-bad-request.json | 94 --------- .../supplemental/status-code-no-content.json | 77 ------- .../supplemental/status-code-other-error.json | 82 -------- .../status-code-service-unavailable.json | 82 -------- exchange/adapter_builders.go | 2 - openrtb_ext/bidders.go | 2 - openrtb_ext/imp_screencore.go | 6 - static/bidder-info/screencore.yaml | 24 +-- static/bidder-params/screencore.json | 22 -- 24 files changed, 12 insertions(+), 2045 deletions(-) delete mode 100644 adapters/screencore/params_test.go delete mode 100644 adapters/screencore/screencore.go delete mode 100644 adapters/screencore/screencore_test.go delete mode 100644 adapters/screencore/screencoretest/exemplary/banner-app.json delete mode 100644 adapters/screencore/screencoretest/exemplary/banner-web.json delete mode 100644 adapters/screencore/screencoretest/exemplary/native-app.json delete mode 100644 adapters/screencore/screencoretest/exemplary/native-web.json delete mode 100644 adapters/screencore/screencoretest/exemplary/video-app.json delete mode 100644 adapters/screencore/screencoretest/exemplary/video-web.json delete mode 100644 adapters/screencore/screencoretest/supplemental/bad_media_type.json delete mode 100644 adapters/screencore/screencoretest/supplemental/empty-imp-array.json delete mode 100644 adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json delete mode 100644 adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json delete mode 100644 adapters/screencore/screencoretest/supplemental/invalid-response.json delete mode 100644 adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json delete mode 100644 adapters/screencore/screencoretest/supplemental/status-code-bad-request.json delete mode 100644 adapters/screencore/screencoretest/supplemental/status-code-no-content.json delete mode 100644 adapters/screencore/screencoretest/supplemental/status-code-other-error.json delete mode 100644 adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json delete mode 100644 openrtb_ext/imp_screencore.go delete mode 100644 static/bidder-params/screencore.json diff --git a/adapters/screencore/params_test.go b/adapters/screencore/params_test.go deleted file mode 100644 index 508731fbde..0000000000 --- a/adapters/screencore/params_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package screencore - -import ( - "encoding/json" - "testing" - - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -var validParams = []string{ - `{ "accountId": "hash", "placementId": "hash"}`, -} - -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.BidderScreencore, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected Screencore params: %s", validParam) - } - } -} - -var invalidParams = []string{ - ``, - `null`, - `true`, - `5`, - `5.2`, - `[]`, - `{}`, - `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, - `{ "placementId": "", "accountId": "" }`, -} - -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.BidderScreencore, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } - } -} diff --git a/adapters/screencore/screencore.go b/adapters/screencore/screencore.go deleted file mode 100644 index 17dab9084b..0000000000 --- a/adapters/screencore/screencore.go +++ /dev/null @@ -1,178 +0,0 @@ -package screencore - -import ( - "encoding/json" - "fmt" - "net/http" - "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" -) - -type adapter struct { - endpoint *template.Template -} - -func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - template, 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: template, - } - return bidder, nil -} - -func getHeaders(request *openrtb2.BidRequest) http.Header { - headers := http.Header{} - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - headers.Add("X-Openrtb-Version", "2.5") - - if request.Device != nil { - if len(request.Device.UA) > 0 { - headers.Add("User-Agent", request.Device.UA) - } - - if len(request.Device.IPv6) > 0 { - headers.Add("X-Forwarded-For", request.Device.IPv6) - } - - if len(request.Device.IP) > 0 { - headers.Add("X-Forwarded-For", request.Device.IP) - } - } - - return headers -} - -func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) { - if len(openRTBRequest.Imp) == 0 { - return nil, []error{&errortypes.BadInput{ - Message: "Empty Imp array in BidRequest", - }} - } - - screencoreExt, err := getImpressionExt(&openRTBRequest.Imp[0]) - if err != nil { - return nil, []error{err} - } - - openRTBRequest.Imp[0].Ext = nil - - url, err := a.buildEndpointURL(screencoreExt) - if err != nil { - return nil, []error{err} - } - - reqJSON, err := json.Marshal(openRTBRequest) - if err != nil { - return nil, []error{err} - } - - return []*adapters.RequestData{{ - Method: http.MethodPost, - Body: reqJSON, - Uri: url, - Headers: getHeaders(openRTBRequest), - ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), - }}, nil -} - -func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtScreencore, error) { - var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - return nil, &errortypes.BadInput{ - Message: "Error parsing screencoreExt - " + err.Error(), - } - } - var screencoreExt openrtb_ext.ExtScreencore - if err := jsonutil.Unmarshal(bidderExt.Bidder, &screencoreExt); err != nil { - return nil, &errortypes.BadInput{ - Message: "Error parsing bidderExt - " + err.Error(), - } - } - - return &screencoreExt, nil -} - -func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtScreencore) (string, error) { - endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID, SourceId: params.PlacementID} - return macros.ResolveMacros(a.endpoint, endpointParams) -} - -func checkResponseStatusCodes(response *adapters.ResponseData) error { - if response.StatusCode == http.StatusServiceUnavailable { - return &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Something went wrong Status Code: [ %d ] ", response.StatusCode), - } - } - - return adapters.CheckResponseStatusCodeForErrors(response) -} - -func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (bidderResponse *adapters.BidderResponse, errs []error) { - if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) { - return nil, nil - } - - httpStatusError := checkResponseStatusCodes(bidderRawResponse) - if httpStatusError != nil { - return nil, []error{httpStatusError} - } - - responseBody := bidderRawResponse.Body - var bidResp openrtb2.BidResponse - if err := jsonutil.Unmarshal(responseBody, &bidResp); err != nil { - return nil, []error{&errortypes.BadServerResponse{ - Message: "Bad Server Response", - }} - } - - if len(bidResp.SeatBid) == 0 { - return nil, []error{&errortypes.BadServerResponse{ - Message: "Empty SeatBid array", - }} - } - - bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) - var bidsArray []*adapters.TypedBid - - for _, sb := range bidResp.SeatBid { - for idx, bid := range sb.Bid { - bidType, err := getMediaTypeForImp(bid) - if err != nil { - return nil, []error{err} - } - - bidsArray = append(bidsArray, &adapters.TypedBid{ - Bid: &sb.Bid[idx], - BidType: bidType, - }) - } - } - - bidResponse.Bids = bidsArray - return bidResponse, nil -} - -func getMediaTypeForImp(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 - default: - return "", fmt.Errorf("unsupported MType %d", bid.MType) - } -} diff --git a/adapters/screencore/screencore_test.go b/adapters/screencore/screencore_test.go deleted file mode 100644 index 2451231fe5..0000000000 --- a/adapters/screencore/screencore_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package screencore - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderScreencore, config.Adapter{ - Endpoint: "http://h1.screencore.io/?kp={{.AccountID}}&kn={{.SourceId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, "screencoretest", bidder) -} diff --git a/adapters/screencore/screencoretest/exemplary/banner-app.json b/adapters/screencore/screencoretest/exemplary/banner-app.json deleted file mode 100644 index 2c807376f7..0000000000 --- a/adapters/screencore/screencoretest/exemplary/banner-app.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "1", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "1", - "banner": { - "w": 320, - "h": 50 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["1"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50, - "mtype": 1 - } - ], - "type": "banner", - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50, - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/exemplary/banner-web.json b/adapters/screencore/screencoretest/exemplary/banner-web.json deleted file mode 100644 index 7e9b12546b..0000000000 --- a/adapters/screencore/screencoretest/exemplary/banner-web.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id1", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - }, - { - "id": "some-impression-id2", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id1", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - } - }, - { - "id": "some-impression-id2", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id1","some-impression-id2"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id1", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50, - "mtype": 1 - }, - { - "id": "a3ae1b4e2fc24a4fb45540082e98e162", - "impid": "some-impression-id2", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50, - "mtype": 1 - } - ], - "type": "banner", - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id1", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "w": 320, - "h": 50, - "mtype": 1 - }, - "type": "banner" - }, - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e162", - "impid": "some-impression-id2", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "w": 320, - "h": 50, - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/exemplary/native-app.json b/adapters/screencore/screencoretest/exemplary/native-app.json deleted file mode 100644 index eb85dcbfec..0000000000 --- a/adapters/screencore/screencoretest/exemplary/native-app.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "native": { - "ver": "1.1", - "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "native": { - "ver": "1.1", - "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "mtype": 4 - } - ], - "type": "native", - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "mtype": 4 - }, - "type": "native" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/exemplary/native-web.json b/adapters/screencore/screencoretest/exemplary/native-web.json deleted file mode 100644 index a597611c23..0000000000 --- a/adapters/screencore/screencoretest/exemplary/native-web.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "native": { - "ver": "1.1", - "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "2607:fb90:f27:4512:d800:cb23:a603:e245" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "native": { - "ver": "1.1", - "request": "{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "mtype": 4 - } - ], - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "mtype": 4 - }, - "type": "native" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/exemplary/video-app.json b/adapters/screencore/screencoretest/exemplary/video-app.json deleted file mode 100644 index 7a29e5b53d..0000000000 --- a/adapters/screencore/screencoretest/exemplary/video-app.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 1280, - "h": 720, - "mtype": 2 - } - ], - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "crid": "20", - "adomain": [ - "awesome.com" - ], - "w": 1280, - "h": 720, - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/exemplary/video-web.json b/adapters/screencore/screencoretest/exemplary/video-web.json deleted file mode 100644 index 47de396e8c..0000000000 --- a/adapters/screencore/screencoretest/exemplary/video-web.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 1280, - "h": 720, - "ext": { - "prebid": { - "type": "video" - } - }, - "mtype": 2 - } - ], - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 1280, - "h": 720, - "ext": { - "prebid": { - "type": "video" - } - }, - "mtype": 2 - }, - "type": "video" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/bad_media_type.json b/adapters/screencore/screencoretest/supplemental/bad_media_type.json deleted file mode 100644 index b8a3994730..0000000000 --- a/adapters/screencore/screencoretest/supplemental/bad_media_type.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "1", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "1", - "banner": { - "w": 320, - "h": 50 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["1"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "test-imp-id", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 320, - "h": 50 - } - ], - "mtype": 0, - "seat": "screencore" - } - ], - "cur": "USD" - } - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "unsupported MType 0", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/empty-imp-array.json b/adapters/screencore/screencoretest/supplemental/empty-imp-array.json deleted file mode 100644 index e19996fbe2..0000000000 --- a/adapters/screencore/screencoretest/supplemental/empty-imp-array.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "expectedMakeRequestsErrors": [ - { - "value": "Empty Imp array in BidRequest", - "comparison": "literal" - } - ], - "mockBidRequest": { - "id": "test-request-id", - "imp": [], - "site": { - "page": "test.com" - } - }, - "httpCalls": [] - } \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json b/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json deleted file mode 100644 index 04058fc917..0000000000 --- a/adapters/screencore/screencoretest/supplemental/empty-seatbid-array.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [], - "cur": "USD" - } - } - } - ], - "mockResponse": { - "status": 200, - "body": "invalid response" - }, - "expectedMakeBidsErrors": [ - { - "value": "Empty SeatBid array", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json b/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json deleted file mode 100644 index 016fbd4349..0000000000 --- a/adapters/screencore/screencoretest/supplemental/invalid-bidder-ext-object.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "expectedMakeRequestsErrors": [ - { - "value": "Error parsing bidderExt - expect { or n, but found \"", - "comparison": "literal" - } - ], - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "some-impression-id", - "tagid": "my-adcode", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": "wrongBidderExt" - } - } - ], - "site": { - "page": "test.com" - } - }, - "httpCalls": [] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/invalid-response.json b/adapters/screencore/screencoretest/supplemental/invalid-response.json deleted file mode 100644 index 79ca5b96dc..0000000000 --- a/adapters/screencore/screencoretest/supplemental/invalid-response.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "banner": { - "w": 320, - "h": 50 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] - }, - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "banner": { - "w": 320, - "h": 50 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" - ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 200, - "body": "invalid response" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Bad Server Response", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json b/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json deleted file mode 100644 index 4c3c9d9505..0000000000 --- a/adapters/screencore/screencoretest/supplemental/invalid-screencore-ext-object.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "expectedMakeRequestsErrors": [ - { - "value": "Error parsing screencoreExt - expect { or n, but found \"", - "comparison": "literal" - } - ], - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "some-impression-id", - "tagid": "my-adcode", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": "wrongscreencoreExt" - } - ], - "site": { - "page": "test.com" - } - }, - "httpCalls": [] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json b/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json deleted file mode 100644 index cb2ac212e8..0000000000 --- a/adapters/screencore/screencoretest/supplemental/status-code-bad-request.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "imp": [ - { - "id": "some-impression-id", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - }, - "tagid": "ogTAGID" - } - ], - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", - "id": "123456789" - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 400 - } - } - ], - "expectedBidResponses": [], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/status-code-no-content.json b/adapters/screencore/screencoretest/supplemental/status-code-no-content.json deleted file mode 100644 index b0315e5703..0000000000 --- a/adapters/screencore/screencoretest/supplemental/status-code-no-content.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 204 - } - } - ], - "expectedBidResponses": [], - "expectedMakeBidsErrors": [] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/status-code-other-error.json b/adapters/screencore/screencoretest/supplemental/status-code-other-error.json deleted file mode 100644 index d35c8b0fa8..0000000000 --- a/adapters/screencore/screencoretest/supplemental/status-code-other-error.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 306 - } - } - ], - "expectedBidResponses": [], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 306. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json b/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json deleted file mode 100644 index f6eb482fa9..0000000000 --- a/adapters/screencore/screencoretest/supplemental/status-code-service-unavailable.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "mockBidRequest": { - "id": "some-request-id", - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "bidder": { - "accountId": "accountId", - "placementId": "placementId" - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "http://h1.screencore.io/?kp=accountId&kn=placementId", - "body": { - "id": "some-request-id", - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - } - } - ], - "site": { - "page": "test.com", - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - }, - "impIDs":["some-impression-id"] - }, - "mockResponse": { - "status": 503 - } - } - ], - "expectedBidResponses": [], - "expectedMakeBidsErrors": [ - { - "value": "Something went wrong Status Code: [ 503 ] ", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 0c81a92e0d..2d2539f047 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -200,7 +200,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/rtbhouse" "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/screencore" "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" "github.com/prebid/prebid-server/v3/adapters/seedtag" "github.com/prebid/prebid-server/v3/adapters/sharethrough" @@ -471,7 +470,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSeedingAlliance: seedingAlliance.Builder, openrtb_ext.BidderSeedtag: seedtag.Builder, openrtb_ext.BidderSaLunaMedia: salunamedia.Builder, - openrtb_ext.BidderScreencore: screencore.Builder, openrtb_ext.BidderSharethrough: sharethrough.Builder, openrtb_ext.BidderShowheroes: showheroes.Builder, openrtb_ext.BidderSilverMob: silvermob.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 91a71c3ecf..5cec0f58e4 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -220,7 +220,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderSeedingAlliance, BidderSeedtag, BidderSaLunaMedia, - BidderScreencore, BidderSharethrough, BidderShowheroes, BidderSilverMob, @@ -593,7 +592,6 @@ const ( BidderSeedingAlliance BidderName = "seedingAlliance" BidderSeedtag BidderName = "seedtag" BidderSaLunaMedia BidderName = "sa_lunamedia" - BidderScreencore BidderName = "screencore" BidderSharethrough BidderName = "sharethrough" BidderShowheroes BidderName = "showheroes" BidderSilverMob BidderName = "silvermob" diff --git a/openrtb_ext/imp_screencore.go b/openrtb_ext/imp_screencore.go deleted file mode 100644 index 5a3fa1c39f..0000000000 --- a/openrtb_ext/imp_screencore.go +++ /dev/null @@ -1,6 +0,0 @@ -package openrtb_ext - -type ExtScreencore struct { - AccountID string `json:"accountId"` - PlacementID string `json:"placementId"` -} diff --git a/static/bidder-info/screencore.yaml b/static/bidder-info/screencore.yaml index 67777a1378..4dd3a19f79 100644 --- a/static/bidder-info/screencore.yaml +++ b/static/bidder-info/screencore.yaml @@ -1,14 +1,14 @@ -endpoint: 'http://h1.screencore.io/?kp={{.AccountID}}&kn={{.SourceId}}' +aliasOf: "teqblaze" +# We have the following regional endpoint domains: 'taqus' - for US_EAST, 'taqeu' - for EU, 'taqapac' - for APAC +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +endpoint: 'https://REGION.screencore.io/pserver' maintainer: email: 'connect@screencore.io' -capabilities: - app: - mediaTypes: - - banner - - video - - native - site: - mediaTypes: - - banner - - video - - native +gvlVendorID: 1473 +userSync: + redirect: + url: "https://cs.screencore.io/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&coppa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://cs.screencore.io/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" diff --git a/static/bidder-params/screencore.json b/static/bidder-params/screencore.json deleted file mode 100644 index 0a181b20f1..0000000000 --- a/static/bidder-params/screencore.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Screencore Adapter Params", - "description": "A schema which validates params accepted by the Screencore adapter", - "type": "object", - "properties": { - "accountId": { - "type": "string", - "description": "Account id", - "minLength": 1 - }, - "placementId": { - "type": "string", - "description": "Placement id", - "minLength": 1 - } - }, - "required": [ - "accountId", - "placementId" - ] -} \ No newline at end of file From 828b830b467c5c55d1e32696a74efafcdfaece63 Mon Sep 17 00:00:00 2001 From: trustXops <prebid@trustx.org> Date: Tue, 3 Feb 2026 16:30:53 +0100 Subject: [PATCH 157/272] New Adapter: TRUSTX (remove Grid alias) (#4614) --- adapters/trustx/params_test.go | 51 +++++ adapters/trustx/trustx.go | 216 ++++++++++++++++++ adapters/trustx/trustx_test.go | 18 ++ .../exemplary/multiple-imp-types.json | 190 +++++++++++++++ .../exemplary/simple-app-banner.json | 146 ++++++++++++ .../exemplary/simple-app-video.json | 141 ++++++++++++ .../exemplary/simple-web-banner.json | 128 +++++++++++ .../exemplary/simple-web-video.json | 146 ++++++++++++ .../supplemental/bad-server-response.json | 95 ++++++++ .../supplemental/bad-status-400.json | 98 ++++++++ .../supplemental/bad-status-500.json | 94 ++++++++ .../supplemental/invalid-bid-ext.json | 133 +++++++++++ .../supplemental/invalid-imp-ext.json | 122 ++++++++++ .../supplemental/no-content-response.json | 89 ++++++++ .../supplemental/unsupported-mtype.json | 122 ++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_trustx.go | 9 + static/bidder-info/trustx.yaml | 22 +- static/bidder-params/trustx.json | 16 ++ 20 files changed, 1834 insertions(+), 6 deletions(-) create mode 100644 adapters/trustx/params_test.go create mode 100644 adapters/trustx/trustx.go create mode 100644 adapters/trustx/trustx_test.go create mode 100644 adapters/trustx/trustxtest/exemplary/multiple-imp-types.json create mode 100644 adapters/trustx/trustxtest/exemplary/simple-app-banner.json create mode 100644 adapters/trustx/trustxtest/exemplary/simple-app-video.json create mode 100644 adapters/trustx/trustxtest/exemplary/simple-web-banner.json create mode 100644 adapters/trustx/trustxtest/exemplary/simple-web-video.json create mode 100644 adapters/trustx/trustxtest/supplemental/bad-server-response.json create mode 100644 adapters/trustx/trustxtest/supplemental/bad-status-400.json create mode 100644 adapters/trustx/trustxtest/supplemental/bad-status-500.json create mode 100644 adapters/trustx/trustxtest/supplemental/invalid-bid-ext.json create mode 100644 adapters/trustx/trustxtest/supplemental/invalid-imp-ext.json create mode 100644 adapters/trustx/trustxtest/supplemental/no-content-response.json create mode 100644 adapters/trustx/trustxtest/supplemental/unsupported-mtype.json create mode 100644 openrtb_ext/imp_trustx.go create mode 100644 static/bidder-params/trustx.json diff --git a/adapters/trustx/params_test.go b/adapters/trustx/params_test.go new file mode 100644 index 0000000000..e0af176ca2 --- /dev/null +++ b/adapters/trustx/params_test.go @@ -0,0 +1,51 @@ +package trustx + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/require" +) + +// This file actually intends to test static/bidder-params/trustx.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.trustx + +// TestValidParams makes sure that the trustx schema accepts all imp.ext fields which we intend to support. +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas") + + for _, validParam := range validParams { + err := validator.Validate(openrtb_ext.BidderTrustX, json.RawMessage(validParam)) + require.NoError(t, err, "Schema rejected trustx params: %s", validParam) + } +} + +// TestInvalidParams makes sure that the trustx schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas") + + for _, invalidParam := range invalidParams { + err := validator.Validate(openrtb_ext.BidderTrustX, json.RawMessage(invalidParam)) + require.Error(t, err, "Schema allowed unexpected params: %s", invalidParam) + } +} + +var validParams = []string{ + `{}`, + `{"uid": 1234}`, + `{"uid": 1234, "keywords":{"site": {}, "user": {}}}`, +} +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{"uid": "invalid_type"}`, + `{"keywords": "invalid_type"}`, +} diff --git a/adapters/trustx/trustx.go b/adapters/trustx/trustx.go new file mode 100644 index 0000000000..3b69f525f4 --- /dev/null +++ b/adapters/trustx/trustx.go @@ -0,0 +1,216 @@ +package trustx + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type impExt struct { + Prebid *openrtb_ext.ExtImpPrebid `json:"prebid,omitempty"` + Bidder json.RawMessage `json:"bidder"` + Data *impExtData `json:"data,omitempty"` + Gpid string `json:"gpid,omitempty"` +} + +type impExtData struct { + PbAdslot string `json:"pbadslot,omitempty"` + AdServer *impExtDataAdServer `json:"adserver,omitempty"` +} + +type impExtDataAdServer struct { + Name string `json:"name,omitempty"` + AdSlot string `json:"adslot,omitempty"` +} + +type bidExt struct { + Bidder bidExtBidder `json:"bidder,omitempty"` +} + +type bidExtBidder struct { + TrustX bidExtBidderTrustX `json:"trustx,omitempty"` +} + +type bidExtBidderTrustX struct { + NetworkName string `json:"networkName,omitempty"` +} + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the TRUSTX adapter for the given bidder with the given config. +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) { + var errs []error + for i := range request.Imp { + err := setImpExtData(&request.Imp[i]) + if err != nil { + errs = append(errs, err) + return nil, errs + } + } + + body, err := jsonutil.Marshal(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + reqs := make([]*adapters.RequestData, 0, 1) + requestData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: body, + Headers: getHeaders(request), + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + reqs = append(reqs, requestData) + + return reqs, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var resp openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &resp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + var bidErrors []error + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1) + for i := range resp.SeatBid { + seatBid := &resp.SeatBid[i] + for j := range seatBid.Bid { + bid := &seatBid.Bid[j] + typedBid, err := getTypedBid(bid) + if err != nil { + bidErrors = append(bidErrors, err) + continue + } + bidderResponse.Bids = append(bidderResponse.Bids, typedBid) + } + } + + return bidderResponse, bidErrors +} + +func setImpExtData(imp *openrtb2.Imp) error { + var ext impExt + if err := jsonutil.Unmarshal(imp.Ext, &ext); err != nil { + //if unmarshalling fails, proceed with the request + return nil + } + if ext.Data != nil && ext.Data.AdServer != nil && ext.Data.AdServer.AdSlot != "" { + ext.Gpid = ext.Data.AdServer.AdSlot + extJSON, err := jsonutil.Marshal(ext) + if err != nil { + return err + } + imp.Ext = extJSON + } + return nil +} + +func getHeaders(request *openrtb2.BidRequest) http.Header { + headers := http.Header{} + headers.Set("Content-Type", "application/json;charset=utf-8") + headers.Set("Accept", "application/json") + headers.Set("X-Openrtb-Version", "2.6") + + if request.Site != nil { + if request.Site.Ref != "" { + headers.Set("Referer", request.Site.Ref) + } + if request.Site.Domain != "" { + headers.Set("Origin", request.Site.Domain) + } + } + + if request.Device != nil { + if len(request.Device.IP) > 0 { + headers.Set("X-Forwarded-For", request.Device.IP) + } + + if len(request.Device.IPv6) > 0 { + headers.Set("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.UA) > 0 { + headers.Set("User-Agent", request.Device.UA) + } + } + + return headers +} + +func getTypedBid(bid *openrtb2.Bid) (*adapters.TypedBid, error) { + var bidType openrtb_ext.BidType + switch bid.MType { + case openrtb2.MarkupBanner: + bidType = openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + bidType = openrtb_ext.BidTypeVideo + default: + return nil, &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unsupported MType: %v", bid.MType), + } + } + + var extBidPrebidVideo *openrtb_ext.ExtBidPrebidVideo + if bidType == openrtb_ext.BidTypeVideo { + extBidPrebidVideo = &openrtb_ext.ExtBidPrebidVideo{} + if len(bid.Cat) > 0 { + extBidPrebidVideo.PrimaryCategory = bid.Cat[0] + } + if bid.Dur > 0 { + extBidPrebidVideo.Duration = int(bid.Dur) + } + } + return &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + BidVideo: extBidPrebidVideo, + BidMeta: getBidMeta(bid.Ext), + }, nil +} + +func getBidMeta(ext json.RawMessage) *openrtb_ext.ExtBidPrebidMeta { + if ext == nil { + return nil + } + var be bidExt + + if err := jsonutil.Unmarshal(ext, &be); err != nil { + return nil + } + var bidMeta *openrtb_ext.ExtBidPrebidMeta + if be.Bidder.TrustX.NetworkName != "" { + bidMeta = &openrtb_ext.ExtBidPrebidMeta{ + NetworkName: be.Bidder.TrustX.NetworkName, + } + } + return bidMeta +} diff --git a/adapters/trustx/trustx_test.go b/adapters/trustx/trustx_test.go new file mode 100644 index 0000000000..dbfc007826 --- /dev/null +++ b/adapters/trustx/trustx_test.go @@ -0,0 +1,18 @@ +package trustx + +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/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderTrustX, config.Adapter{ + Endpoint: "https://test.localhost.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + require.NoError(t, buildErr, "Builder returned unexpected error") + adapterstest.RunJSONBidderTest(t, "trustxtest", bidder) +} diff --git a/adapters/trustx/trustxtest/exemplary/multiple-imp-types.json b/adapters/trustx/trustxtest/exemplary/multiple-imp-types.json new file mode 100644 index 0000000000..6e0f3511ee --- /dev/null +++ b/adapters/trustx/trustxtest/exemplary/multiple-imp-types.json @@ -0,0 +1,190 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + }, + { + "id": "test-imp-2", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Origin": [ + "test-domain.com" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + }, + { + "id": "test-imp-2", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "device": { + "ip": "123.123.123.123", + "ua": "ua" + }, + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index" + } + }, + "impIDs": [ + "test-imp", + "test-imp-2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + }, + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d708", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d223", + "price": 10, + "impid": "test-imp-2", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + } + ], + "seat": "trustx" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + }, + "type": "video", + "video": { + "duration": 15, + "primary_category": "IAB3-8" + } + }, + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d708", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d223", + "price": 10, + "impid": "test-imp-2", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} + diff --git a/adapters/trustx/trustxtest/exemplary/simple-app-banner.json b/adapters/trustx/trustxtest/exemplary/simple-app-banner.json new file mode 100644 index 0000000000..14351d090d --- /dev/null +++ b/adapters/trustx/trustxtest/exemplary/simple-app-banner.json @@ -0,0 +1,146 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "data": { + "adserver": { + "adslot": "test_ad_slot" + } + }, + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ua": "ua", + "ip": "123.123.123.123" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.localhost.com", + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "gpid": "test_ad_slot", + "data": { + "adserver": { + "adslot": "test_ad_slot" + } + }, + "bidder": { + "uid": 1234 + } + } + } + ], + "device": { + "ua": "ua", + "ip": "123.123.123.123" + }, + "app": { + "bundle": "app-bundle" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<img src=\"demo ad\" width=\"300\" height=\"250\">", + "mtype": 1, + "ext": { + "bidder": { + "trustx": { + "networkName": "test-network" + } + } + } + } + ] + } + ], + "seat": "trustx" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<img src=\"demo ad\" width=\"300\" height=\"250\">", + "mtype": 1, + "ext": { + "bidder": { + "trustx": { + "networkName": "test-network" + } + } + } + }, + "meta": { + "networkName": "test-network" + }, + "type": "banner" + } + ], + "seat": "trustx" + } + ] +} diff --git a/adapters/trustx/trustxtest/exemplary/simple-app-video.json b/adapters/trustx/trustxtest/exemplary/simple-app-video.json new file mode 100644 index 0000000000..5bd5deee4c --- /dev/null +++ b/adapters/trustx/trustxtest/exemplary/simple-app-video.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + } + ], + "seat": "trustx" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + }, + "type": "video", + "video": { + "duration": 15, + "primary_category": "IAB3-8" + } + } + ] + } + ] +} + diff --git a/adapters/trustx/trustxtest/exemplary/simple-web-banner.json b/adapters/trustx/trustxtest/exemplary/simple-web-banner.json new file mode 100644 index 0000000000..5771a229b9 --- /dev/null +++ b/adapters/trustx/trustxtest/exemplary/simple-web-banner.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index", + "ref": "https://example.com/page" + }, + "device": { + "ua": "ua", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Origin": [ + "test-domain.com" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + ], + "Referer": [ + "https://example.com/page" + ] + }, + "uri": "https://test.localhost.com", + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index", + "ref": "https://example.com/page" + }, + "device": { + "ua": "ua", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + } + ] + } + ], + "seat": "trustx" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + }, + "type": "banner" + } + ], + "seat": "trustx" + } + ] +} diff --git a/adapters/trustx/trustxtest/exemplary/simple-web-video.json b/adapters/trustx/trustxtest/exemplary/simple-web-video.json new file mode 100644 index 0000000000..aee0c04e99 --- /dev/null +++ b/adapters/trustx/trustxtest/exemplary/simple-web-video.json @@ -0,0 +1,146 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Origin": [ + "test-domain.com" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + } + ], + "seat": "trustx" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "w": 1920, + "h": 1080, + "mtype": 2, + "dur": 15, + "cat": [ + "IAB3-8" + ] + }, + "type": "video", + "video": { + "duration": 15, + "primary_category": "IAB3-8" + } + } + ] + } + ] +} + diff --git a/adapters/trustx/trustxtest/supplemental/bad-server-response.json b/adapters/trustx/trustxtest/supplemental/bad-server-response.json new file mode 100644 index 0000000000..7f5221585c --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/bad-server-response.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} + diff --git a/adapters/trustx/trustxtest/supplemental/bad-status-400.json b/adapters/trustx/trustxtest/supplemental/bad-status-400.json new file mode 100644 index 0000000000..0786d48891 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/bad-status-400.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.org/index" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Origin": [ + "test-domain.com" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.localhost.com", + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.org/index" + }, + "device": { + "ua": "ua", + "ip": "123.123.123.123" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/trustx/trustxtest/supplemental/bad-status-500.json b/adapters/trustx/trustxtest/supplemental/bad-status-500.json new file mode 100644 index 0000000000..53e49da220 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/bad-status-500.json @@ -0,0 +1,94 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} + diff --git a/adapters/trustx/trustxtest/supplemental/invalid-bid-ext.json b/adapters/trustx/trustxtest/supplemental/invalid-bid-ext.json new file mode 100644 index 0000000000..17f20ad731 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/invalid-bid-ext.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ua": "ua", + "ip": "123.123.123.123" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "https://test.localhost.com", + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "device": { + "ua": "ua", + "ip": "123.123.123.123" + }, + "app": { + "bundle": "app-bundle" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<img src=\"demo ad\" width=\"300\" height=\"250\">", + "mtype": 1, + "ext": { + "bidder": { + "trustx": { + "networkName": 1 + } + } + } + } + ] + } + ], + "seat": "trustx" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<img src=\"demo ad\" width=\"300\" height=\"250\">", + "mtype": 1, + "ext": { + "bidder": { + "trustx": { + "networkName": 1 + } + } + } + }, + "type": "banner", + "meta": {} + } + ], + "seat": "trustx" + } + ] +} diff --git a/adapters/trustx/trustxtest/supplemental/invalid-imp-ext.json b/adapters/trustx/trustxtest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..8260bae301 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/invalid-imp-ext.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "tagid": "123", + "banner": { + "w": 300, + "h": 250 + }, + "ext": 1 + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index", + "ref": "https://example.com/page" + }, + "device": { + "ua": "ua", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Origin": [ + "test-domain.com" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + ], + "Referer": [ + "https://example.com/page" + ] + }, + "uri": "https://test.localhost.com", + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "tagid": "123", + "banner": { + "w": 300, + "h": 250 + }, + "ext": 1 + } + ], + "site": { + "domain": "test-domain.com", + "page": "http://test-domain.com/index", + "ref": "https://example.com/page" + }, + "device": { + "ua": "ua", + "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + } + ] + } + ], + "seat": "trustx" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "crid": "4235d4b1-e2a6-9bbb-a34c-766714c2d221", + "price": 10, + "impid": "test-imp", + "adm": "<iframe width=\"300\" height=\"250\"></iframe>", + "mtype": 1 + }, + "type": "banner" + } + ], + "seat": "trustx" + } + ] +} diff --git a/adapters/trustx/trustxtest/supplemental/no-content-response.json b/adapters/trustx/trustxtest/supplemental/no-content-response.json new file mode 100644 index 0000000000..5d65dc0e73 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/no-content-response.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} + diff --git a/adapters/trustx/trustxtest/supplemental/unsupported-mtype.json b/adapters/trustx/trustxtest/supplemental/unsupported-mtype.json new file mode 100644 index 0000000000..0596f43cf5 --- /dev/null +++ b/adapters/trustx/trustxtest/supplemental/unsupported-mtype.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "https://test.localhost.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ], + "User-Agent": [ + "ua" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "body": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "uid": 1234 + } + } + } + ], + "app": { + "bundle": "app-bundle" + }, + "device": { + "ip": "123.123.123.123", + "ua": "ua" + } + }, + "impIDs": [ + "test-imp" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request", + "seatbid": [ + { + "bid": [ + { + "id": "2315f4a3-f2c4-8cac-69de-985272e1d706", + "impid": "test-imp", + "price": 10, + "adm": "test-ad", + "crid": "creative", + "w": 1920, + "h": 1080, + "mtype": 0, + "dur": 15 + } + ], + "seat": "trustx" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unsupported MType: 0", + "comparison": "literal" + } + ] +} + diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 2d2539f047..9a2aaa0bd2 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -235,6 +235,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/triplelift" "github.com/prebid/prebid-server/v3/adapters/triplelift_native" "github.com/prebid/prebid-server/v3/adapters/trustedstack" + "github.com/prebid/prebid-server/v3/adapters/trustx" "github.com/prebid/prebid-server/v3/adapters/ucfunnel" "github.com/prebid/prebid-server/v3/adapters/undertone" "github.com/prebid/prebid-server/v3/adapters/unicorn" @@ -503,6 +504,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderTriplelift: triplelift.Builder, openrtb_ext.BidderTripleliftNative: triplelift_native.Builder, openrtb_ext.BidderTrustedstack: trustedstack.Builder, + openrtb_ext.BidderTrustX: trustx.Builder, openrtb_ext.BidderUcfunnel: ucfunnel.Builder, openrtb_ext.BidderUndertone: undertone.Builder, openrtb_ext.BidderUnicorn: unicorn.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 5cec0f58e4..8cd543c1f1 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -253,6 +253,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderTriplelift, BidderTripleliftNative, BidderTrustedstack, + BidderTrustX, BidderUcfunnel, BidderUndertone, BidderUnicorn, @@ -625,6 +626,7 @@ const ( BidderTriplelift BidderName = "triplelift" BidderTripleliftNative BidderName = "triplelift_native" BidderTrustedstack BidderName = "trustedstack" + BidderTrustX BidderName = "trustx" BidderUcfunnel BidderName = "ucfunnel" BidderUndertone BidderName = "undertone" BidderUnicorn BidderName = "unicorn" diff --git a/openrtb_ext/imp_trustx.go b/openrtb_ext/imp_trustx.go new file mode 100644 index 0000000000..8187f91a2c --- /dev/null +++ b/openrtb_ext/imp_trustx.go @@ -0,0 +1,9 @@ +package openrtb_ext + +import "encoding/json" + +// ExtImpTrustX defines the contract for bidrequest.imp[i].ext.prebid.bidder.trustx +type ExtImpTrustX struct { + Uid int `json:"uid"` + Keywords json.RawMessage `json:"keywords,omitempty"` +} diff --git a/static/bidder-info/trustx.yaml b/static/bidder-info/trustx.yaml index 1c60ac34c2..878d1d1d23 100644 --- a/static/bidder-info/trustx.yaml +++ b/static/bidder-info/trustx.yaml @@ -1,9 +1,19 @@ -aliasOf: grid +endpoint: "https://ads.trustx.org/pbs" maintainer: - email: "grid-tech@themediagrid.com" -gvlVendorID: 686 + email: "prebid@trustx.org" +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video userSync: + iframe: + url: "https://static.cdn.trustx.org/x/user_sync.html?source=pbs&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "$UID" redirect: - url: "https://x.bidswitch.net/check_uuid/{{.RedirectURL}}?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}" - userMacro: "${BSW_UUID}" - \ No newline at end of file + url: "https://sync.trustx.org/usync-pbs?us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "$UID" diff --git a/static/bidder-params/trustx.json b/static/bidder-params/trustx.json new file mode 100644 index 0000000000..7560642aae --- /dev/null +++ b/static/bidder-params/trustx.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TRUSTX Adapter Params", + "description": "A schema which validates params accepted by the TRUSTX adapter", + "type": "object", + "properties": { + "uid": { + "type": "integer", + "description": "The ad slot id" + }, + "keywords": { + "type": "object", + "description": "Keywords" + } + } +} From c6afd83c3f489b67ef723306bcbb5c0d0a43044a Mon Sep 17 00:00:00 2001 From: Scott Kay <noreply@syntaxnode.com> Date: Tue, 3 Feb 2026 17:16:05 -0500 Subject: [PATCH 158/272] Deprecate Embedded Certs (#4625) --- config/config.go | 3 - config/config_test.go | 2 - router/router.go | 7 +- server/ssl/ssl.go | 3650 +--------------------------------------- server/ssl/ssl_test.go | 56 +- 5 files changed, 27 insertions(+), 3691 deletions(-) diff --git a/config/config.go b/config/config.go index e8f23b4ace..ec3f501d92 100644 --- a/config/config.go +++ b/config/config.go @@ -79,8 +79,6 @@ type Configuration struct { AccountDefaults Account `mapstructure:"account_defaults"` // accountDefaultsJSON is the internal serialized form of AccountDefaults used for json merge accountDefaultsJSON json.RawMessage - // CertsUseSystem will use the host OS certificates instead of embedded certs. - CertsUseSystem bool `mapstructure:"certificates_use_system"` // Local private file containing SSL certificates PemCertsFile string `mapstructure:"certificates_file"` // Custom headers to handle request timeouts from queueing infrastructure @@ -1253,7 +1251,6 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("compression.response.enable_gzip", false) v.SetDefault("compression.request.enable_gzip", false) - v.SetDefault("certificates_use_system", false) v.SetDefault("certificates_file", "") v.SetDefault("auto_gen_source_tid", true) diff --git a/config/config_test.go b/config/config_test.go index 7d7ebe9101..b216fe4a48 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -600,7 +600,6 @@ analytics: - code: agma-code publisher_id: publisher-id site_app_id: site-or-app-id -certificates_use_system: true `) func cmpStrings(t *testing.T, key, expected, actual string) { @@ -949,7 +948,6 @@ func TestFullConfig(t *testing.T) { cmpStrings(t, "analytics.agma.accounts.0.publisher_id", "publisher-id", cfg.Analytics.Agma.Accounts[0].PublisherId) cmpStrings(t, "analytics.agma.accounts.0.code", "agma-code", cfg.Analytics.Agma.Accounts[0].Code) cmpStrings(t, "analytics.agma.accounts.0.site_app_id", "site-or-app-id", cfg.Analytics.Agma.Accounts[0].SiteAppId) - cmpBools(t, "certificates_use_system", true, cfg.CertsUseSystem) } func TestValidateConfig(t *testing.T) { diff --git a/router/router.go b/router/router.go index 87e88324c9..8dab7ade56 100644 --- a/router/router.go +++ b/router/router.go @@ -128,15 +128,14 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R Router: httprouter.New(), } - // For bid processing, we need both the hardcoded certificates and the certificates found in container's - // local file system - certPool, certPoolCreateErr := ssl.CreateCertPool(cfg.CertsUseSystem) + certPool, certPoolCreateErr := ssl.CreateCertPool() if certPoolCreateErr != nil { logger.Infof("Could not load root certificates: %s \n", certPoolCreateErr.Error()) } + // load optional PEM certificate files var readCertErr error - certPool, readCertErr = ssl.AppendPEMFileToRootCAPool(certPool, cfg.PemCertsFile) + certPool, readCertErr = ssl.AppendPEMFileToCertPool(certPool, cfg.PemCertsFile) if readCertErr != nil { logger.Infof("Could not read certificates file: %s \n", readCertErr.Error()) } diff --git a/server/ssl/ssl.go b/server/ssl/ssl.go index ee754ed66d..6a69f6de2e 100644 --- a/server/ssl/ssl.go +++ b/server/ssl/ssl.go @@ -2,3664 +2,30 @@ package ssl import ( "crypto/x509" - "errors" "fmt" "os" ) -// from https://medium.com/@kelseyhightower/optimizing-docker-images-for-static-binaries-b5696e26eb07 - -var ( - ErrLoadEmbeddedCerts = errors.New("failed to load embedded certs") -) - -func CreateCertPool(useSystem bool) (*x509.CertPool, error) { - if useSystem { - return x509.SystemCertPool() - } - - return createCertPoolFromEmbedded() +func CreateCertPool() (*x509.CertPool, error) { + return x509.SystemCertPool() } -func createCertPoolFromEmbedded() (*x509.CertPool, error) { - pool := x509.NewCertPool() - - if ok := pool.AppendCertsFromPEM(pemCerts); !ok { - return pool, ErrLoadEmbeddedCerts - } - - return pool, nil -} - -// Appends certificates to the `x509.CertPool` from a `.pem` private local file. On many Linux -// systems, /etc/ssl/cert.pem will contain the system wide set but in our case, we'll pull -// the certificate file path from the `Configuration` struct -func AppendPEMFileToRootCAPool(certPool *x509.CertPool, pemFileName string) (*x509.CertPool, error) { +// AppendPEMFileToCertPool appends certificates from a PEM file to the provided certificate pool. +// This is a helper method intended for use in main startup code to append specific certificates +// to the system certificate pool. +func AppendPEMFileToCertPool(certPool *x509.CertPool, pemFileName string) (*x509.CertPool, error) { if certPool == nil { certPool = x509.NewCertPool() } + if pemFileName != "" { - //read file and place it's contents in `pemCerts` pemCerts, err := os.ReadFile(pemFileName) if err != nil { return certPool, fmt.Errorf("Failed to read file %s: %v", pemFileName, err) } - //`pemCerts` has been obtained, append to certPool certPool.AppendCertsFromPEM(pemCerts) } + return certPool, nil } - -var pemCerts = []byte(` ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV -BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk -YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV -BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN -MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF -UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD -VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v -dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj -cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q -yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH -2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX -H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL -zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR -p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz -W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ -SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn -LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 -n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B -u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L -9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej -rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK -pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 -vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq -OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ -/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 -2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI -+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 -MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo -tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP -Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr -ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL -MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 -yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr -VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ -nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG -XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj -vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt -Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g -N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC -nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y -YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua -kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL -QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp -6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG -yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i -QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO -tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu -QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ -Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u -olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 -x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz -dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG -A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U -cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf -qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ -JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ -+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS -s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 -HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 -70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG -V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S -qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S -5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia -C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX -OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE -FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 -KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B -8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ -MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc -0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ -u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF -u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH -YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 -GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO -RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e -KeC2uAloGRwYQw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w -LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w -CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 -MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF -Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI -zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X -tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 -AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 -KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD -aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu -CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo -9H1/IISpQuQo ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM -MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx -MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 -MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD -QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z -4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv -Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ -kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs -GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln -nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh -3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD -0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy -geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 -ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB -c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI -pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS -4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs -o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ -qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw -xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM -rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 -AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR -0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY -o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 -dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE -oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 -MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc -tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd -IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j -b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC -AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw -ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m -iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF -Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ -hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P -Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE -EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV -1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t -CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR -5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw -f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 -ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK -GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU -MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI -T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz -MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF -SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh -bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z -xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ -spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 -58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR -at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll -5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq -nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK -V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ -pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO -z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn -jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ -WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF -7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 -YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli -awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u -+2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 -X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN -SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo -P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI -+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz -znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 -eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 -YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy -r/6zcCwupvI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw -CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ -VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy -MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ -TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS -b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B -IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ -+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK -sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA -94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B -43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw -CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu -bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ -BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s -eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK -+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 -QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 -hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm -ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG -BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw -PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy -dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 -YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 -1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT -vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed -aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 -1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 -r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 -cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ -wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ -6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA -2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH -Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR -eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB -/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u -d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr -PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d -8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi -1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd -rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di -taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 -lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj -yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn -Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy -yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n -wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 -OV+KmalBWQewLK8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 -MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu -MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV -BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw -MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg -U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ -n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q -p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq -NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF -8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 -HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa -mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi -7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF -ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P -qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ -v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 -Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD -ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 -WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo -zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR -5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ -GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf -5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq -0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D -P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM -qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP -0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf -E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw -TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t -bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa -Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv -cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C -flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE -hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq -hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg -2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS -Um9poIyNStDuiw7LR47QjRE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw -TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t -bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa -Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv -cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL -j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU -v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq -hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n -ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV -mkzw5l4lIhVtwodZ0LKOag== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL -BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi -Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 -NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t -U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt -MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk -YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh -suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al -DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj -WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl -P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547 -KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p -UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/ -kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO -Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB -Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U -CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ -KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 -NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ -nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+ -QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v -trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a -aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD -j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4 -Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w -lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn -YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc -icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL -BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi -Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 -NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t -U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt -MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE -NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0 -kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C -rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz -hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2 -LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs -n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku -FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5 -kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3 -wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v -wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs -5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ -KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB -KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3 -+VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme -APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq -pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT -6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF -sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt -PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d -lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 -v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O -rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 -NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS -zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 -QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ -VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW -wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV -dWNbFJWcHwHP2NVypw87 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 -NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC -/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD -wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 -OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA -y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb -gfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp -Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 -MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ -bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS -7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp -0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS -B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 -BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ -LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 -DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT -HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN -NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs -IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ -ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 -2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp -wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM -pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD -nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po -sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx -Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd -Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX -KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe -XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL -tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv -TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw -GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H -PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF -O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ -REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik -AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv -/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ -p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw -MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF -qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK -ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 -MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub -j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo -U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b -u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ -bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er -fF6adulZkMV8gzURZVE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG -A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 -d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu -dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq -RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy -MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD -VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g -Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi -A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt -ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH -Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC -R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX -hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 -cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs -IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz -dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy -NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu -dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt -dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 -aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T -RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN -cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW -wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 -U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 -jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN -BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ -jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ -Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v -1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R -nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH -VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw -gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL -Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg -MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw -BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 -MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 -c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ -bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ -2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E -T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j -5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM -C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T -DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX -wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A -2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm -nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl -N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj -c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS -5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS -Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr -hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ -B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI -AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw -H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ -b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk -2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol -IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk -5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY -n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG -A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw -FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx -MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u -aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b -RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z -YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 -QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw -yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ -BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ -SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH -r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 -4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me -dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw -q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 -nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu -H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA -VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC -XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd -6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf -+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi -kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 -wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB -TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C -MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn -4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I -aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy -qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt -nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY -6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu -MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k -RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg -f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV -+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo -dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW -Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa -G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq -gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H -vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 -0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC -B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u -NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg -yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev -HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 -xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR -TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg -JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV -7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl -6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G -jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 -4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 -VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm -ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi -QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR -HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D -9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 -p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD -VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw -MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g -UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT -BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx -uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV -HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ -+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 -bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw -CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh -cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v -dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG -A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj -aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg -Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 -KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y -STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD -AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw -SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN -nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs -MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg -Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL -MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl -YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv -b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l -mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE -4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv -a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M -pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw -Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b -LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY -AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB -AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq -E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr -W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ -CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU -X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 -f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja -H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP -JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P -zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt -jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 -/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT -BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 -aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW -xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU -63ZTGI0RmLo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa -Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 -YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw -qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv -Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 -lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz -Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ -KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK -FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj -HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr -y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ -/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM -a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 -fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG -SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi -7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc -SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza -ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc -XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg -iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho -L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF -Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr -kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ -vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU -YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL -BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ -SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n -a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 -NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT -CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u -Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO -dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI -VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV -9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY -2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY -vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt -bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb -x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ -l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK -TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj -Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw -DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG -7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk -MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr -gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk -GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS -3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm -Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ -l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c -JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP -L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa -LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG -mpv0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT -U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 -MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh -dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm -acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN -SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME -GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW -uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp -15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN -b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO -MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD -DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX -DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw -b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP -L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY -t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins -S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 -PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO -L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 -R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w -dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS -+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS -d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG -AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f -gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z -NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt -hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM -QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf -R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ -DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW -P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy -lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq -bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w -AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q -r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji -Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU -98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw -CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T -ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN -MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG -A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT -ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC -WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ -6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B -Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa -qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q -4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf -MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD -Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw -HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY -MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp -YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa -ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz -SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf -iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X -ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 -IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS -VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE -SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu -+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt -8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L -HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt -zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P -AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c -mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ -YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 -gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA -Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB -JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX -DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui -TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 -dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 -LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp -0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY -QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr -MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG -A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 -MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp -Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD -QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz -i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 -h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV -MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 -UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni -8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC -h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD -VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB -AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm -KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ -X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr -QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 -pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN -QSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT -AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD -VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx -NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT -HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 -IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl -dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK -ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu -9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O -be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV -BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw -JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2 -MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc -U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg -Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r -CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA -lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG -TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7 -9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7 -8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4 -g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we -GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst -+3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M -0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ -T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw -HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS -YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA -FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd -9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI -UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+ -OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke -gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf -iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV -nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD -2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI// -1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad -TdJ0MN1kURXbg4NR16/9M51NZg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu -IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow -RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY -U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv -Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br -YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF -nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH -6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt -eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ -c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ -MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH -HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf -jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 -5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB -rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c -wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB -AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp -WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 -xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ -2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ -IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 -aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X -em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR -dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ -OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ -hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy -tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw -NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv -b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD -VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F -VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 -7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X -Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ -/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs -81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm -dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe -Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu -sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 -pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs -slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ -arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG -9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl -dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj -TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed -Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 -Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI -OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 -vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW -t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn -HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx -SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx -CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE -AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 -NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ -MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq -AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 -vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 -lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD -n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT -7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o -6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC -TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 -WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R -DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI -pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj -YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy -rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ -8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi -0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM -A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS -SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K -TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF -6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er -3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt -Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT -VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW -ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA -rBPuUBQemMc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM -BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe -Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw -IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU -cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS -T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK -AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 -nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep -qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA -yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs -hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX -zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv -kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT -f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA -uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih -MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E -BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 -wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 -XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 -JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j -ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV -VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx -xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on -AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d -7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj -gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV -+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo -FGWsJwt0ivKH ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw -WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y -MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD -VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz -dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx -s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw -LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD -pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE -AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR -UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj -/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw -CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x -ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 -c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx -OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI -SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn -swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu -7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 -1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW -80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP -JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l -RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw -hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 -coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc -BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n -twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W -0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe -uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q -lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB -aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE -sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT -MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe -qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh -VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 -h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 -EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK -yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN -FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w -DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw -CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh -DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB -BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ -j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF -1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G -A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 -AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC -MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu -Sw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL -BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg -Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv -b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG -EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u -IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ -n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd -2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF -VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ -GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF -li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU -r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 -eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb -MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg -jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB -7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW -5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE -ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 -90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z -xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu -QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 -FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH -22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP -xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn -dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 -Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b -nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ -CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH -u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj -d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw -RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY -BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz -MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u -LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 -v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd -e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw -V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA -AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG -GJTO ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL -BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x -FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx -MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s -THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc -IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU -AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ -GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 -8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH -flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt -J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim -0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN -pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ -UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW -OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB -AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet -8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd -nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j -bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM -Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv -TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS -S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr -I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 -b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB -UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P -Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven -sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= ------END CERTIFICATE----- -`) diff --git a/server/ssl/ssl_test.go b/server/ssl/ssl_test.go index b425ec9a63..ef1925b50e 100644 --- a/server/ssl/ssl_test.go +++ b/server/ssl/ssl_test.go @@ -8,49 +8,25 @@ import ( "github.com/stretchr/testify/require" ) -func TestCertsFromFilePoolExists(t *testing.T) { - // Load hardcoded certificates found in ssl.go - certPool, certErr := createCertPoolFromEmbedded() - require.NoError(t, certErr) - - // Assert loaded certificates by looking at the length of the subjects array of strings - subjects := certPool.Subjects() - hardCodedSubNum := len(subjects) - assert.True(t, hardCodedSubNum > 0) - - // Load certificates from file - certificatesFile := "mockcertificates/mock-certs.pem" - certPool, err := AppendPEMFileToRootCAPool(certPool, certificatesFile) - - // Assert loaded certificates by looking at the length of the subjects array of strings - assert.NoError(t, err, "Error thrown by AppendPEMFileToRootCAPool while loading file %s: %v", certificatesFile, err) - subjects = certPool.Subjects() - subNumIncludingFile := len(subjects) - assert.True(t, subNumIncludingFile > hardCodedSubNum, "subNumIncludingFile should be greater than hardCodedSubNum") -} - -func TestCertsFromFilePoolDontExist(t *testing.T) { - // Empty certpool - var certPool *x509.CertPool = nil +func TestAppendPEMFileToCertPool(t *testing.T) { + t.Run("append-to-empty", func(t *testing.T) { + var certPool *x509.CertPool = nil - // Load certificates from file - certificatesFile := "mockcertificates/mock-certs.pem" - certPool, err := AppendPEMFileToRootCAPool(certPool, certificatesFile) + certificatesFile := "mockcertificates/mock-certs.pem" + certPool, err := AppendPEMFileToCertPool(certPool, certificatesFile) - // Assert loaded certificates by looking at the length of the subjects array of strings - assert.NoError(t, err, "Error thrown by AppendPEMFileToRootCAPool while loading file %s: %v", certificatesFile, err) - subjects := certPool.Subjects() - assert.Equal(t, len(subjects), 1, "We only loaded one certificate from the file, len(subjects) should equal 1") -} + require.NoError(t, err) + subjects := certPool.Subjects() + assert.Equal(t, len(subjects), 1) + }) -func TestAppendPEMFileToRootCAPoolFail(t *testing.T) { - // Empty certpool - var certPool *x509.CertPool + t.Run("fail", func(t *testing.T) { + var certPool *x509.CertPool - // In this test we are going to pass a file that does not exist as value of second argument - fakeCertificatesFile := "mockcertificates/NO-FILE.pem" - _, err := AppendPEMFileToRootCAPool(certPool, fakeCertificatesFile) + certificatesFile := "mockcertificates/NO-FILE.pem" + _, err := AppendPEMFileToCertPool(certPool, certificatesFile) - // Assert AppendPEMFileToRootCAPool correctly throws an error when trying to load an nonexisting file - assert.Errorf(t, err, "AppendPEMFileToRootCAPool should throw an error by while loading fake file %s \n", fakeCertificatesFile) + // expect an error from a file which doesn't exist + assert.Error(t, err) + }) } From f336eb79c121c691e4dd2831d86226b74ecc4338 Mon Sep 17 00:00:00 2001 From: Gabriel Gravel <gravelg@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:44:43 -0500 Subject: [PATCH 159/272] Scope3: Add rtd targeting in seatbid (#4606) --- modules/scope3/rtd/README.md | 19 +- modules/scope3/rtd/async_request.go | 2 +- modules/scope3/rtd/module.go | 205 +++++------ modules/scope3/rtd/module_test.go | 553 ++++++++++++++++++++++------ 4 files changed, 534 insertions(+), 245 deletions(-) diff --git a/modules/scope3/rtd/README.md b/modules/scope3/rtd/README.md index 3db4d447e2..bdaa5e5893 100644 --- a/modules/scope3/rtd/README.md +++ b/modules/scope3/rtd/README.md @@ -19,10 +19,12 @@ hooks: auth_key: ${SCOPE3_API_KEY} # Set SCOPE3_API_KEY environment variable endpoint: https://rtdp.scope3.com/prebid/prebid timeout_ms: 1000 - cache_ttl_seconds: 60 # Cache segments for 60 seconds (default) - add_to_targeting: false # Set to true to add segments as individual targeting keys for GAM - masking: # Optional privacy masking configuration - enabled: true # Enable field masking before sending to Scope3 + cache_ttl_seconds: 60 # Cache segments for 60 seconds (default) + add_to_targeting: false # Set to true to add segments as individual targeting keys for GAM + add_scope3_targeting_section: false # Also set targeting in dedicated scope3 section + single_segment_key: "" # When set, adds all segments as a comma separated value under a single targeting key + masking: # Optional privacy masking configuration + enabled: true # Enable field masking before sending to Scope3 geo: preserve_metro: true # Preserve DMA code (default: true) preserve_zip: true # Preserve postal code (default: true) @@ -46,12 +48,12 @@ hooks: hook_sequence: - module_code: "scope3.rtd" hook_impl_code: "HandleEntrypointHook" - raw_auction_request: + auction_processed: groups: - timeout: 2000 hook_sequence: - module_code: "scope3.rtd" - hook_impl_code: "HandleRawAuctionHook" + hook_impl_code: "HandleAuctionProcessedHook" auction_response: groups: - timeout: 5 @@ -73,6 +75,7 @@ hooks: "timeout_ms": 1000, "cache_ttl_seconds": 60, "add_to_targeting": false, + "add_scope3_targeting_section": false, "masking": { "enabled": true, "geo": { @@ -306,7 +309,7 @@ The module forwards any fields that are not masked from the bid request to the S ### Auction Response Data The module adds audience segments to the auction response, giving publishers full control over how to use them: -1. **Publisher Flexibility**: Segments are always returned in `ext.scope3.segments` for the publisher to decide where to send +1. **Publisher Flexibility**: Segments are returned in `ext.scope3.segments` when configured for the publisher to decide where to send 2. **Google Ad Manager (GAM)**: Individual targeting keys are added when `add_to_targeting: true` (e.g., `gmp_eligible=true`) 3. **Other Ad Servers**: Publisher can forward segments to any ad server or system 4. **Analytics**: Segment data is available for reporting and analysis @@ -314,7 +317,7 @@ The module adds audience segments to the auction response, giving publishers ful ### Response Format Options The module provides segments in two formats: -**Always available:** +**When `add_scope3_targeting_section: true`:** ```json { "ext": { diff --git a/modules/scope3/rtd/async_request.go b/modules/scope3/rtd/async_request.go index 38c4663286..23f44b2df5 100644 --- a/modules/scope3/rtd/async_request.go +++ b/modules/scope3/rtd/async_request.go @@ -48,6 +48,6 @@ func (ar *AsyncRequest) fetchScope3SegmentsAsync(request *openrtb2.BidRequest) { } close(ar.Done) }() - ar.Segments, ar.Err = ar.Module.fetchScope3Segments(ar.Context, request) + ar.Segments, ar.Err = ar.fetchScope3Segments(ar.Context, request) }() } diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go index 15fab4fc68..9b80534a0c 100644 --- a/modules/scope3/rtd/module.go +++ b/modules/scope3/rtd/module.go @@ -10,9 +10,7 @@ import ( "errors" "fmt" "hash" - "maps" "net/http" - "slices" "strings" "sync" "time" @@ -26,6 +24,7 @@ import ( "github.com/prebid/prebid-server/v3/modules/moduledeps" "github.com/prebid/prebid-server/v3/util/iterutil" "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/tidwall/sjson" ) // Builder is the entry point for the module @@ -90,31 +89,35 @@ func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, e const ( // keys for miCtx - asyncRequestKey = "scope3.AsyncRequest" - scope3MacroKey = "scope3_macro" - scope3MacroSeparator = ";" + asyncRequestKey = "scope3.AsyncRequest" + scope3MacroKey = "scope3_macro" + scope3IncludeKey = "scope3_include" + scope3Separator = ";" + scope3CacheKeySeparator = "|" ) -var scope3MacroKeyPlusSeparator = scope3MacroKey + scope3MacroSeparator +var scope3MacroKeyPlusSeparator = scope3MacroKey + scope3Separator +var scope3IncludeKeyPlusSeparator = scope3IncludeKey + scope3Separator const DefaultScope3RTDURL = "https://rtdp.scope3.com/prebid/prebid" var ( // Declare hooks - _ hookstage.Entrypoint = (*Module)(nil) - _ hookstage.RawAuctionRequest = (*Module)(nil) - _ hookstage.AuctionResponse = (*Module)(nil) + _ hookstage.Entrypoint = (*Module)(nil) + _ hookstage.ProcessedAuctionRequest = (*Module)(nil) + _ hookstage.AuctionResponse = (*Module)(nil) ) // Config holds module configuration type Config struct { - Endpoint string `json:"endpoint"` - AuthKey string `json:"auth_key"` - Timeout int `json:"timeout_ms"` - CacheTTL int `json:"cache_ttl_seconds"` // Cache segments for this many seconds - CacheSize int `json:"cache_size"` // Maximum size of segment cache in bytes - AddToTargeting bool `json:"add_to_targeting"` // Add segments as individual targeting keys - Masking MaskingConfig `json:"masking"` // Privacy masking configuration + Endpoint string `json:"endpoint"` + AuthKey string `json:"auth_key"` + Timeout int `json:"timeout_ms"` + CacheTTL int `json:"cache_ttl_seconds"` // Cache segments for this many seconds + CacheSize int `json:"cache_size"` // Maximum size of segment cache in bytes + AddToTargeting bool `json:"add_to_targeting"` // Add segments as individual targeting keys + AddScope3TargetingSection bool `json:"add_scope3_targeting_section"` // Add segments as individual targeting keys in Scope3 targeting section + Masking MaskingConfig `json:"masking"` // Privacy masking configuration } // MaskingConfig controls what user data is masked before sending to Scope3 @@ -153,30 +156,19 @@ type userExt struct { // Response types for Scope3 API type Scope3Response struct { - Data []Scope3Data `json:"data"` + AEESignals `json:"aee_signals"` } -type Scope3Data struct { - Destination string `json:"destination"` - Imp []Scope3ImpData `json:"imp"` +type AEESignals struct { + Include []string `json:"include,omitempty"` + Exclude []string `json:"exclude,omitempty"` + Macro string `json:"macro,omitempty"` // base64 + Bidders []map[string]Bidder `json:"bidders,omitempty"` } -type Scope3ImpData struct { - ID string `json:"id"` - Ext *Scope3Ext `json:"ext,omitempty"` -} - -type Scope3Ext struct { - Scope3 *Scope3ExtData `json:"scope3"` -} - -type Scope3ExtData struct { - Segments []Scope3Segment `json:"segments"` - Macro string `json:"macro"` -} - -type Scope3Segment struct { - ID string `json:"id"` +type Bidder struct { + Segments []string `json:"segments,omitempty"` + Deals []string `json:"deals,omitempty"` } // Module implements the Scope3 RTD module @@ -203,13 +195,13 @@ func (m *Module) HandleEntrypointHook( } // HandleRawAuctionHook is called early in the auction to fetch Scope3 data -func (m *Module) HandleRawAuctionHook( +func (m *Module) HandleProcessedAuctionHook( ctx context.Context, miCtx hookstage.ModuleInvocationContext, - payload hookstage.RawAuctionRequestPayload, -) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) { - var ret hookstage.HookResult[hookstage.RawAuctionRequestPayload] - analyticsNamePrefix := "HandleRawAuctionHook." + payload hookstage.ProcessedAuctionRequestPayload, +) (hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload], error) { + var ret hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload] + analyticsNamePrefix := "HandleProcessedAuctionHook." asyncRequest, ok := miCtx.ModuleContext[asyncRequestKey].(*AsyncRequest) if !ok { @@ -227,25 +219,8 @@ func (m *Module) HandleRawAuctionHook( return ret, nil } - // Parse OpenRTB request here rather than HandleProcessedAuctionHook to get a copy to avoid parallel mutation issues - var bidRequest openrtb2.BidRequest - if err := jsonutil.Unmarshal(payload, &bidRequest); err != nil { - // Log error but don't fail the auction - ret.AnalyticsTags = hookanalytics.Analytics{ - Activities: []hookanalytics.Activity{{ - Name: analyticsNamePrefix + "bidRequest.unmarshal", - Status: hookanalytics.ActivityStatusError, - Results: []hookanalytics.Result{{ - Status: hookanalytics.ResultStatusError, - Values: map[string]interface{}{"error": err.Error()}, - }}, - }}, - } - return ret, nil - } - // Start async request to Scope3 - asyncRequest.fetchScope3SegmentsAsync(&bidRequest) + asyncRequest.fetchScope3SegmentsAsync(payload.Request.BidRequest) return ret, nil } @@ -313,50 +288,64 @@ func (m *Module) HandleAuctionResponseHook( // Add segments to the auction response ret.ChangeSet.AddMutation( func(payload hookstage.AuctionResponsePayload) (hookstage.AuctionResponsePayload, error) { - // Add Scope3 segments to the response ext so publisher can use them - if payload.BidResponse.Ext == nil { - payload.BidResponse.Ext = json.RawMessage("{}") - } - - var extMap map[string]interface{} - if err = jsonutil.Unmarshal(payload.BidResponse.Ext, &extMap); err != nil { - extMap = make(map[string]interface{}) - } - // Add segments as individual targeting keys for GAM integration if m.cfg.AddToTargeting { - prebidMap, ok := extMap["prebid"].(map[string]interface{}) - if !ok { - prebidMap = make(map[string]interface{}) - extMap["prebid"] = prebidMap - } - targetingMap, ok := prebidMap["targeting"].(map[string]interface{}) - if !ok { - targetingMap = make(map[string]interface{}) - prebidMap["targeting"] = targetingMap - } // Add each segment as individual targeting key for _, segment := range segments { - if strings.HasPrefix(segment, scope3MacroKeyPlusSeparator) { - macroKeyVal := strings.Split(segment, scope3MacroSeparator) - if len(macroKeyVal) != 2 { - continue - } - targetingMap[macroKeyVal[0]] = macroKeyVal[1] - } else { - targetingMap[segment] = "true" + segmentKeyVal := strings.Split(segment, scope3Separator) + if len(segmentKeyVal) != 2 { + logger.Infof("Skipping malformed segment: %s", segment) + continue + } + newPayload, err := sjson.SetBytes(payload.BidResponse.Ext, "prebid.targeting."+segmentKeyVal[0], segmentKeyVal[1]) + if err != nil { + logger.Errorf("Failed to add targeting to bid: %v", err) + continue } + payload.BidResponse.Ext = newPayload } } - // Always add to a dedicated scope3 section for publisher flexibility - extMap["scope3"] = map[string]interface{}{ - "segments": segments, + // Add to a dedicated scope3 section for publisher flexibility when configured + if m.cfg.AddScope3TargetingSection { + newPayload, err := sjson.SetBytes(payload.BidResponse.Ext, "scope3.segments", segments) + if err != nil { + logger.Errorf("Failed to add scope3 section to bid response ext: %v", err) + } else { + payload.BidResponse.Ext = newPayload + } } - extResp, err := jsonutil.Marshal(extMap) - if err == nil { - payload.BidResponse.Ext = extResp + // also add to seatbid[].bid[] + for seatBid := range iterutil.SlicePointerValues(payload.BidResponse.SeatBid) { + for bid := range iterutil.SlicePointerValues(seatBid.Bid) { + // Add segments as individual targeting keys for GAM integration + if m.cfg.AddToTargeting { + for _, segment := range segments { + segmentKeyVal := strings.Split(segment, scope3Separator) + if len(segmentKeyVal) != 2 { + logger.Infof("Skipping malformed segment in bid targeting: %s", segment) + continue + } + newPayload, err := sjson.SetBytes(bid.Ext, "prebid.targeting."+segmentKeyVal[0], segmentKeyVal[1]) + if err != nil { + logger.Errorf("Failed to add targeting to bid: %v", err) + continue + } + bid.Ext = newPayload + } + } + + // Always add to a dedicated scope3 section for publisher flexibility + if m.cfg.AddScope3TargetingSection { + newPayload, err := sjson.SetBytes(bid.Ext, "scope3.segments", segments) + if err != nil { + logger.Errorf("Failed to add scope3 section to bid response ext: %v", err) + } else { + bid.Ext = newPayload + } + } + } } return payload, nil @@ -375,7 +364,7 @@ func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.B // Check cache first if segments, err := m.cache.Get(cacheKey); err == nil { - return strings.Split(string(segments), ","), nil + return strings.Split(string(segments), scope3CacheKeySeparator), nil } // Apply privacy masking before sending to Scope3 @@ -421,31 +410,17 @@ func (m *Module) fetchScope3Segments(ctx context.Context, bidRequest *openrtb2.B return nil, err } - // Extract unique segments (exclude destination) - segmentMap := make(map[string]bool) - var macro string - for data := range iterutil.SlicePointerValues(scope3Resp.Data) { - // Extract actual segments from impression-level data - for imp := range iterutil.SlicePointerValues(data.Imp) { - if imp.Ext != nil && imp.Ext.Scope3 != nil { - if imp.Ext.Scope3.Macro != "" { - macro = imp.Ext.Scope3.Macro - } - for segment := range iterutil.SlicePointerValues(imp.Ext.Scope3.Segments) { - segmentMap[segment.ID] = true - } - } - } + segments := []string{} + if len(scope3Resp.Include) > 0 { + segmentsStr := scope3IncludeKeyPlusSeparator + strings.Join(scope3Resp.Include, ",") + segments = append(segments, segmentsStr) } - - // Convert to slice - segments := slices.AppendSeq(make([]string, 0, len(segmentMap)), maps.Keys(segmentMap)) - if macro != "" { - segments = append(segments, scope3MacroKeyPlusSeparator+macro) + if scope3Resp.Macro != "" { + segments = append(segments, scope3MacroKeyPlusSeparator+scope3Resp.Macro) } // Cache the result - err = m.cache.Set(cacheKey, []byte(strings.Join(segments, ",")), m.cfg.CacheTTL) + err = m.cache.Set(cacheKey, []byte(strings.Join(segments, scope3CacheKeySeparator)), m.cfg.CacheTTL) if err != nil { logger.Infof("could not set segments in cache: %v", err) } diff --git a/modules/scope3/rtd/module_test.go b/modules/scope3/rtd/module_test.go index 8b46d3bbb8..041d549f25 100644 --- a/modules/scope3/rtd/module_test.go +++ b/modules/scope3/rtd/module_test.go @@ -17,6 +17,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -128,25 +129,13 @@ func TestScope3APIIntegration(t *testing.T) { // Return mock Scope3 response with segments response := `{ - "data": [ - { - "destination": "triplelift.com", - "imp": [ - { - "id": "test-imp-1", - "ext": { - "scope3": { - "macro": "test-macro", - "segments": [ - {"id": "gmp_eligible"}, - {"id": "gmp_plus_eligible"} - ] - } - } - } - ] - } - ] + "aee_signals": { + "include": [ + "gmp_eligible", + "gmp_plus_eligible" + ], + "macro": "test-macro" + } }` w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -197,34 +186,153 @@ func TestScope3APIIntegration(t *testing.T) { ctx := context.Background() segments, err := module.fetchScope3Segments(ctx, bidRequest) require.NoError(t, err) - assert.Len(t, segments, 3) - assert.ElementsMatch(t, segments, []string{"gmp_eligible", "gmp_plus_eligible", "scope3_macro;test-macro"}) - assert.NotContains(t, segments, "triplelift.com") // Should not include destination + assert.Len(t, segments, 2) + assert.ElementsMatch(t, segments, []string{"scope3_include;gmp_eligible,gmp_plus_eligible", "scope3_macro;test-macro"}) } -func TestScope3APIIntegrationWithTargeting(t *testing.T) { - // Create mock server that returns segments +func TestScope3APIIntegrationNoSegments(t *testing.T) { + // Create mock Scope3 API server mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify request method and headers + assert.Equal(t, "POST", r.Method) + assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + assert.Equal(t, "test-auth-key", r.Header.Get("x-scope3-auth")) + + // Return mock Scope3 response with segments response := `{ - "data": [ + "aee_signals": {} + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with mock server endpoint + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "cache_ttl_seconds": 60, + "add_to_targeting": false + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Create test bid request + width := int64(300) + height := int64(250) + bidRequest := &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test-page", + }, + User: &openrtb2.User{ + ID: "test-user", + Ext: json.RawMessage(`{ + "eids": [ + { + "source": "liveramp.com", + "uids": [{"id": "test-ramp-id"}] + } + ] + }`), + }, + } + + // Test fetchScope3Segments + ctx := context.Background() + segments, err := module.fetchScope3Segments(ctx, bidRequest) + require.NoError(t, err) + assert.Len(t, segments, 0) + + // Test entrypoint hook + entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) + require.NoError(t, err) + assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + + payload := hookstage.ProcessedAuctionRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: bidRequest, + }, + } + + // Test raw auction hook + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: entrypointResult.ModuleContext, + } + _, err = module.HandleProcessedAuctionHook(ctx, miCtx, payload) + require.NoError(t, err) + + // Test auction response hook + responsePayload := hookstage.AuctionResponsePayload{ + BidResponse: &openrtb2.BidResponse{ + ID: "test-response", + Ext: json.RawMessage(`{}`), + SeatBid: []openrtb2.SeatBid{ { - "destination": "triplelift.com", - "imp": [ + Seat: "test-seat", + Bid: []openrtb2.Bid{ { - "id": "test-imp-1", - "ext": { - "scope3": { - "macro": "test-macro", - "segments": [ - {"id": "test_segment_1"}, - {"id": "test_segment_2"} - ] - } - } - } - ] - } - ] + ID: "test-bid-1", + ImpID: "test-imp-1", + Price: 1.0, + Ext: json.RawMessage(`{}`), + }, + { + ID: "test-bid-2", + ImpID: "test-imp-2", + Price: 2.0, + Ext: json.RawMessage(`{}`), + }, + }, + }, + }, + }, + } + + responseResult, err := module.HandleAuctionResponseHook(ctx, miCtx, responsePayload) + require.NoError(t, err) + + // Verify the response was modified + assert.True(t, len(responseResult.ChangeSet.Mutations()) > 0) + + // Apply the mutations and check the result + modifiedPayload := responsePayload + for _, mutation := range responseResult.ChangeSet.Mutations() { + var err error + modifiedPayload, err = mutation.Apply(modifiedPayload) + require.NoError(t, err) + } + + // Parse the modified response + var extMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.Ext, &extMap) + require.NoError(t, err) + + // Verify scope3 section exists + _, exists := extMap["scope3"].(map[string]interface{}) + require.False(t, exists) +} + +func TestScope3APIIntegrationWithTargeting(t *testing.T) { + // Create mock server that returns segments + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{ + "aee_signals": { + "include": [ + "test_segment_1", + "test_segment_2" + ], + "macro": "test-macro" + } }` w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -237,7 +345,8 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { "endpoint": "` + mockServer.URL + `", "auth_key": "test-auth-key", "timeout_ms": 1000, - "add_to_targeting": true + "add_to_targeting": true, + "add_scope3_targeting_section": true }`) moduleInterface, err := Builder(config, getTestModuleDeps(t)) @@ -255,24 +364,32 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { // Create test request payload width := int64(300) height := int64(250) - bidRequest := openrtb2.BidRequest{ - ID: "test-auction", - Imp: []openrtb2.Imp{{ - ID: "test-imp-1", - Banner: &openrtb2.Banner{W: &width, H: &height}, - }}, - Site: &openrtb2.Site{ - Domain: "example.com", - Page: "https://example.com/test", + payload := hookstage.ProcessedAuctionRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{ + { + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }, + { + ID: "test-imp-2", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + }, }, } - requestPayload, _ := json.Marshal(bidRequest) // Test raw auction hook miCtx := hookstage.ModuleInvocationContext{ ModuleContext: entrypointResult.ModuleContext, } - _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + _, err = module.HandleProcessedAuctionHook(ctx, miCtx, payload) require.NoError(t, err) // Test auction response hook @@ -280,6 +397,42 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { BidResponse: &openrtb2.BidResponse{ ID: "test-response", Ext: json.RawMessage(`{}`), + SeatBid: []openrtb2.SeatBid{ + { + Seat: "test-seat", + Bid: []openrtb2.Bid{ + { + ID: "test-bid-1", + ImpID: "test-imp-1", + Price: 1.0, + Ext: json.RawMessage(`{}`), + }, + { + ID: "test-bid-2", + ImpID: "test-imp-2", + Price: 2.0, + Ext: json.RawMessage(`{}`), + }, + }, + }, + { + Seat: "test-seat2", + Bid: []openrtb2.Bid{ + { + ID: "test-bid-3", + ImpID: "test-imp-3", + Price: 1.0, + Ext: json.RawMessage(`{}`), + }, + { + ID: "test-bid-4", + ImpID: "test-imp-4", + Price: 2.0, + Ext: json.RawMessage(`{}`), + }, + }, + }, + }, }, } @@ -307,7 +460,158 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { require.True(t, exists) segments, exists := scope3Data["segments"].([]interface{}) require.True(t, exists) - assert.Len(t, segments, 3) + assert.Len(t, segments, 2) + + // Verify targeting section exists (add_to_targeting: true) + prebidData, exists := extMap["prebid"].(map[string]interface{}) + require.True(t, exists, "prebid section missing") + targetingData, exists := prebidData["targeting"].(map[string]interface{}) + require.True(t, exists, "targeting section missing") + + // Check individual targeting keys + assert.Equal(t, "test_segment_1,test_segment_2", targetingData["scope3_include"]) + assert.Equal(t, "test-macro", targetingData["scope3_macro"]) + + // check seatbid + assert.Len(t, modifiedPayload.BidResponse.SeatBid, 2) + assert.Len(t, modifiedPayload.BidResponse.SeatBid[0].Bid, 2) + assert.Len(t, modifiedPayload.BidResponse.SeatBid[1].Bid, 2) + + for _, seatbid := range modifiedPayload.BidResponse.SeatBid { + for _, bid := range seatbid.Bid { + // Parse the modified response + var extBidMap map[string]interface{} + err = json.Unmarshal(bid.Ext, &extBidMap) + require.NoError(t, err) + + // Verify scope3 section exists + scope3DataSeatBid, exists := extBidMap["scope3"].(map[string]interface{}) + require.True(t, exists, "scope3 section missing") + segmentsSeatBid, exists := scope3DataSeatBid["segments"].([]interface{}) + require.True(t, exists, "segments section missing") + assert.Len(t, segmentsSeatBid, 2) + + // Verify targeting section exists (add_to_targeting: true) + prebidDataSeatBid, exists := extBidMap["prebid"].(map[string]interface{}) + require.True(t, exists, "prebid section missing") + targetingDataSeatBid, exists := prebidDataSeatBid["targeting"].(map[string]interface{}) + require.True(t, exists, "targeting section missing") + + // Check individual targeting keys + assert.Equal(t, "test_segment_1,test_segment_2", targetingDataSeatBid["scope3_include"]) + assert.Equal(t, "test-macro", targetingDataSeatBid["scope3_macro"]) + } + } +} + +func TestScope3APIIntegrationWithTargetingNoScope3Section(t *testing.T) { + // Create mock server that returns segments + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := `{ + "aee_signals": { + "include": [ + "test_segment_1", + "test_segment_2" + ], + "macro": "test-macro" + } + }` + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(response)) + })) + defer mockServer.Close() + + // Create module with targeting enabled + config := json.RawMessage(`{ + "endpoint": "` + mockServer.URL + `", + "auth_key": "test-auth-key", + "timeout_ms": 1000, + "add_to_targeting": true, + "add_scope3_targeting_section": false + }`) + + moduleInterface, err := Builder(config, getTestModuleDeps(t)) + require.NoError(t, err) + module := moduleInterface.(*Module) + + // Test full hook workflow + ctx := context.Background() + + // Test entrypoint hook + entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) + require.NoError(t, err) + assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + + // Create test request payload + width := int64(300) + height := int64(250) + payload := hookstage.ProcessedAuctionRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + }, + }, + } + + // Test raw auction hook + miCtx := hookstage.ModuleInvocationContext{ + ModuleContext: entrypointResult.ModuleContext, + } + _, err = module.HandleProcessedAuctionHook(ctx, miCtx, payload) + require.NoError(t, err) + + // Test auction response hook + responsePayload := hookstage.AuctionResponsePayload{ + BidResponse: &openrtb2.BidResponse{ + ID: "test-response", + Ext: json.RawMessage(`{}`), + SeatBid: []openrtb2.SeatBid{ + { + Seat: "test-seat", + Bid: []openrtb2.Bid{ + { + ID: "test-bid-1", + ImpID: "test-imp-1", + Price: 1.0, + Ext: json.RawMessage(`{}`), + }, + }, + }, + }, + }, + } + + responseResult, err := module.HandleAuctionResponseHook(ctx, miCtx, responsePayload) + require.NoError(t, err) + + // Verify the response was modified + assert.True(t, len(responseResult.ChangeSet.Mutations()) > 0) + + // Apply the mutations and check the result + modifiedPayload := responsePayload + for _, mutation := range responseResult.ChangeSet.Mutations() { + var err error + modifiedPayload, err = mutation.Apply(modifiedPayload) + require.NoError(t, err) + } + + // Parse the modified response + var extMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.Ext, &extMap) + require.NoError(t, err) + + // Verify scope3 section exists + _, exists := extMap["scope3"].(map[string]interface{}) + require.False(t, exists) // Verify targeting section exists (add_to_targeting: true) prebidData, exists := extMap["prebid"].(map[string]interface{}) @@ -316,33 +620,44 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { require.True(t, exists) // Check individual targeting keys - assert.Equal(t, "true", targetingData["test_segment_1"]) - assert.Equal(t, "true", targetingData["test_segment_2"]) + assert.Equal(t, "test_segment_1,test_segment_2", targetingData["scope3_include"]) assert.Equal(t, "test-macro", targetingData["scope3_macro"]) + + // check seatbid + assert.Len(t, modifiedPayload.BidResponse.SeatBid, 1) + assert.Len(t, modifiedPayload.BidResponse.SeatBid[0].Bid, 1) + + // Parse the modified response + var extBidMap map[string]interface{} + err = json.Unmarshal(modifiedPayload.BidResponse.SeatBid[0].Bid[0].Ext, &extBidMap) + require.NoError(t, err) + + // Verify scope3 section exists + _, exists = extBidMap["scope3"].(map[string]interface{}) + require.False(t, exists) + + // Verify targeting section exists (add_to_targeting: true) + prebidDataSeatBid, exists := extBidMap["prebid"].(map[string]interface{}) + require.True(t, exists, "prebid section missing") + targetingDataSeatBid, exists := prebidDataSeatBid["targeting"].(map[string]interface{}) + require.True(t, exists, "targeting section missing") + + // Check individual targeting keys + assert.Equal(t, "test_segment_1,test_segment_2", targetingDataSeatBid["scope3_include"]) + assert.Equal(t, "test-macro", targetingDataSeatBid["scope3_macro"]) } func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { // Create mock server that returns segments mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { response := `{ - "data": [ - { - "destination": "triplelift.com", - "imp": [ - { - "id": "test-imp-1", - "ext": { - "scope3": { - "segments": [ - {"id": "test_segment_1"}, - {"id": "test_segment_2"} - ] - } - } - } - ] - } - ] + "aee_signals": { + "include": [ + "test_segment_1", + "test_segment_2" + ], + "macro": "test-macro" + } }` w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -355,7 +670,8 @@ func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { "endpoint": "` + mockServer.URL + `", "auth_key": "test-auth-key", "timeout_ms": 1000, - "add_to_targeting": true + "add_to_targeting": true, + "add_scope3_targeting_section": true }`) moduleInterface, err := Builder(config, getTestModuleDeps(t)) @@ -373,24 +689,27 @@ func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { // Create test request payload width := int64(300) height := int64(250) - bidRequest := openrtb2.BidRequest{ - ID: "test-auction", - Imp: []openrtb2.Imp{{ - ID: "test-imp-1", - Banner: &openrtb2.Banner{W: &width, H: &height}, - }}, - Site: &openrtb2.Site{ - Domain: "example.com", - Page: "https://example.com/test", + payload := hookstage.ProcessedAuctionRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + }, }, } - requestPayload, _ := json.Marshal(bidRequest) // Test raw auction hook miCtx := hookstage.ModuleInvocationContext{ ModuleContext: entrypointResult.ModuleContext, } - _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + _, err = module.HandleProcessedAuctionHook(ctx, miCtx, payload) require.NoError(t, err) // Test auction response hook @@ -434,33 +753,21 @@ func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { require.True(t, exists) // Check individual targeting keys - assert.Equal(t, "true", targetingData["segment_existing"]) - assert.Equal(t, "true", targetingData["test_segment_1"]) - assert.Equal(t, "true", targetingData["test_segment_2"]) + assert.Equal(t, "test_segment_1,test_segment_2", targetingData["scope3_include"]) + assert.Equal(t, "test-macro", targetingData["scope3_macro"]) } func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { // Create mock server that returns segments mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { response := `{ - "data": [ - { - "destination": "triplelift.com", - "imp": [ - { - "id": "test-imp-1", - "ext": { - "scope3": { - "segments": [ - {"id": "test_segment_1"}, - {"id": "test_segment_2"} - ] - } - } - } - ] - } - ] + "aee_signals": { + "include": [ + "test_segment_1", + "test_segment_2" + ], + "macro": "test-macro" + } }` w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -473,7 +780,8 @@ func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { "endpoint": "` + mockServer.URL + `", "auth_key": "test-auth-key", "timeout_ms": 1000, - "add_to_targeting": true + "add_to_targeting": true, + "add_scope3_targeting_section": true }`) moduleInterface, err := Builder(config, getTestModuleDeps(t)) @@ -491,24 +799,27 @@ func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { // Create test request payload width := int64(300) height := int64(250) - bidRequest := openrtb2.BidRequest{ - ID: "test-auction", - Imp: []openrtb2.Imp{{ - ID: "test-imp-1", - Banner: &openrtb2.Banner{W: &width, H: &height}, - }}, - Site: &openrtb2.Site{ - Domain: "example.com", - Page: "https://example.com/test", + payload := hookstage.ProcessedAuctionRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + ID: "test-auction", + Imp: []openrtb2.Imp{{ + ID: "test-imp-1", + Banner: &openrtb2.Banner{W: &width, H: &height}, + }}, + Site: &openrtb2.Site{ + Domain: "example.com", + Page: "https://example.com/test", + }, + }, }, } - requestPayload, _ := json.Marshal(bidRequest) // Test raw auction hook miCtx := hookstage.ModuleInvocationContext{ ModuleContext: entrypointResult.ModuleContext, } - _, err = module.HandleRawAuctionHook(ctx, miCtx, requestPayload) + _, err = module.HandleProcessedAuctionHook(ctx, miCtx, payload) require.NoError(t, err) // Test auction response hook @@ -552,8 +863,8 @@ func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { require.True(t, exists) // Check individual targeting keys - assert.Equal(t, "true", targetingData["test_segment_1"]) - assert.Equal(t, "true", targetingData["test_segment_2"]) + assert.Equal(t, "test_segment_1,test_segment_2", targetingData["scope3_include"]) + assert.Equal(t, "test-macro", targetingData["scope3_macro"]) } func TestScope3APIError(t *testing.T) { From 797692ad2a3ed4ab46a8f714f1cf6bcd74b5b085 Mon Sep 17 00:00:00 2001 From: Ankit Karwa <37686606+karwaankit32@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:10:29 +0530 Subject: [PATCH 160/272] Fix: Prevent duplicate account IDs in HTTP account fetcher query params (#4648) Co-authored-by: Ankit Karwa <ankitkarwa@microsoft.com> --- .../backends/http_fetcher/fetcher.go | 2 +- .../backends/http_fetcher/fetcher_test.go | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go index c28d782e01..1950f2c3ee 100644 --- a/stored_requests/backends/http_fetcher/fetcher.go +++ b/stored_requests/backends/http_fetcher/fetcher.go @@ -119,7 +119,7 @@ func (fetcher *HttpFetcher) FetchAccounts(ctx context.Context, accountIDs []stri if len(accountIDs) == 0 { return nil, nil } - u := fetcher.EndpointURL + u := *fetcher.EndpointURL q := u.Query() if !fetcher.UseRfcCompliantBuilder { q.Set("account-ids", `["`+strings.Join(accountIDs, `","`)+`"]`) diff --git a/stored_requests/backends/http_fetcher/fetcher_test.go b/stored_requests/backends/http_fetcher/fetcher_test.go index 9d014eaf5a..6dfa12b250 100644 --- a/stored_requests/backends/http_fetcher/fetcher_test.go +++ b/stored_requests/backends/http_fetcher/fetcher_test.go @@ -241,6 +241,64 @@ func TestFetchAccountRfcCompliant(t *testing.T) { assert.JSONEq(t, `{"disabled": true, "id":"acc-1"}`, string(account), "Unexpected account data fetching existing account") } +func TestFetchAccountsDoesNotAccumulateQueryParams(t *testing.T) { + var seen [][]string + + handler := func(w http.ResponseWriter, r *http.Request) { + got := richSplit(r.URL.Query().Get("account-ids")) + seen = append(seen, got) + + // Validate and respond using existing helper + newAccountHandler(t, got, false)(w, r) + } + + server := httptest.NewServer(http.HandlerFunc(handler)) + defer server.Close() + + fetcher := NewFetcher(server.Client(), server.URL, false) + + // first fetcher call + _, errs := fetcher.FetchAccounts(context.Background(), []string{"acc-1"}) + assert.Empty(t, errs) + + // second fetcher call with different account ID + _, errs = fetcher.FetchAccounts(context.Background(), []string{"acc-2"}) + assert.Empty(t, errs) + + assert.Equal(t, 2, len(seen)) + assert.Equal(t, []string{"acc-1"}, seen[0]) + assert.Equal(t, []string{"acc-2"}, seen[1]) +} + +func TestFetchAccountsDoesNotAccumulateQueryParamsRfcCompliant(t *testing.T) { + var seen [][]string + + handler := func(w http.ResponseWriter, r *http.Request) { + got := r.URL.Query()["account-id"] + seen = append(seen, got) + + // true flag for RFC compliant + newAccountHandler(t, got, true)(w, r) + } + + server := httptest.NewServer(http.HandlerFunc(handler)) + defer server.Close() + + fetcher := NewFetcher(server.Client(), server.URL, true) + + // first fetcher call + _, errs := fetcher.FetchAccounts(context.Background(), []string{"acc-1"}) + assert.Empty(t, errs) + + // second fetcher call with different account ID + _, errs = fetcher.FetchAccounts(context.Background(), []string{"acc-2"}) + assert.Empty(t, errs) + + assert.Equal(t, 2, len(seen)) + assert.Equal(t, []string{"acc-1"}, seen[0]) + assert.Equal(t, []string{"acc-2"}, seen[1]) +} + func TestFetchAccount(t *testing.T) { fetcher, close := newTestAccountFetcher(t, []string{"acc-1"}, false) defer close() From 590af5fe3c2f2e6d1f41b162e16a87b8e52fff51 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:28:19 -0500 Subject: [PATCH 161/272] Mark video endpoint as deprecated (#4691) --- config/config.go | 7 ++++ config/config_test.go | 4 +++ endpoints/openrtb2/video_auction.go | 6 ++++ endpoints/openrtb2/video_auction_test.go | 42 +++++++++++++++++++++--- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index ec3f501d92..2c3acefab2 100644 --- a/config/config.go +++ b/config/config.go @@ -50,6 +50,7 @@ type Configuration struct { CategoryMapping StoredRequests `mapstructure:"category_mapping"` VTrack VTrack `mapstructure:"vtrack"` Event Event `mapstructure:"event"` + Video Video `mapstructure:"video"` Accounts StoredRequests `mapstructure:"accounts"` UserSync UserSync `mapstructure:"user_sync"` // Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives. @@ -550,6 +551,10 @@ type Event struct { TimeoutMS int64 `mapstructure:"timeout_ms"` } +type Video struct { + EnableDeprecatedEndpoint bool `mapstructure:"enable_deprecated_endpoint"` +} + type HostCookie struct { Domain string `mapstructure:"domain"` Family string `mapstructure:"family"` @@ -1123,6 +1128,8 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("event.timeout_ms", 1000) + v.SetDefault("video.enable_deprecated_endpoint", false) + v.SetDefault("user_sync.priority_groups", [][]string{}) v.SetDefault("accounts.filesystem.enabled", false) diff --git a/config/config_test.go b/config/config_test.go index b216fe4a48..c17226ded0 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -168,6 +168,7 @@ func TestDefaults(t *testing.T) { cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "video.enable_deprecated_endpoint", false, cfg.Video.EnableDeprecatedEndpoint) cmpBools(t, "accounts.filesystem.enabled", false, cfg.Accounts.Files.Enabled) cmpStrings(t, "accounts.filesystem.directorypath", "./stored_requests/data/by_id", cfg.Accounts.Files.Path) cmpStrings(t, "accounts.http.endpoint", "", cfg.Accounts.HTTP.Endpoint) @@ -422,6 +423,8 @@ gdpr: vendor_exceptions: ["foo10"] special_feature1: vendor_exceptions: ["fooSP1"] +video: + enable_deprecated_endpoint: true ccpa: enforce: true lmt: @@ -685,6 +688,7 @@ func TestFullConfig(t *testing.T) { cmpInts(t, "http_client_cache.idle_connection_timeout_seconds", 3, cfg.CacheClient.IdleConnTimeout) cmpInts(t, "gdpr.host_vendor_id", 15, cfg.GDPR.HostVendorID) cmpStrings(t, "gdpr.default_value", "1", cfg.GDPR.DefaultValue) + cmpBools(t, "video.enable_deprecated_endpoint", true, cfg.Video.EnableDeprecatedEndpoint) cmpStrings(t, "host_schain_node.asi", "pbshostcompany.com", cfg.HostSChainNode.ASI) cmpStrings(t, "host_schain_node.sid", "00001", cfg.HostSChainNode.SID) cmpStrings(t, "host_schain_node.rid", "BidRequest", cfg.HostSChainNode.RID) diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index 047511f379..9b7a9a3bea 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -122,6 +122,12 @@ func NewVideoEndpoint( func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { start := time.Now() + if !deps.cfg.Video.EnableDeprecatedEndpoint { + w.WriteHeader(http.StatusNotImplemented) + w.Write([]byte("The video endpoint is deprecated and will be removed in 5.0. You may re-enable it via the host configuration setting video.enable_deprecated_endpoint")) + return + } + vo := analytics.VideoObject{ Status: http.StatusOK, Errors: make([]error, 0), diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go index cd3e0d9c37..2ba5cea684 100644 --- a/endpoints/openrtb2/video_auction_test.go +++ b/endpoints/openrtb2/video_auction_test.go @@ -1273,7 +1273,7 @@ func mockDepsWithMetrics(t *testing.T, ex *mockExchangeVideo) (*endpointDeps, *m &mockVideoStoredReqFetcher{}, &mockVideoStoredReqFetcher{}, &mockAccountFetcher{data: mockVideoAccountData}, - &config.Configuration{MaxRequestSize: maxSize}, + &config.Configuration{Video: config.Video{EnableDeprecatedEndpoint: true}, MaxRequestSize: maxSize}, metrics, mockModule, map[string]string{}, @@ -1324,7 +1324,7 @@ func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps { &mockVideoStoredReqFetcher{}, &mockVideoStoredReqFetcher{}, &mockAccountFetcher{data: mockVideoAccountData}, - &config.Configuration{MaxRequestSize: maxSize}, + &config.Configuration{Video: config.Video{EnableDeprecatedEndpoint: true}, MaxRequestSize: maxSize}, &metricsConfig.NilMetricsEngine{}, analyticsBuild.New(&config.Analytics{}), map[string]string{}, @@ -1349,7 +1349,7 @@ func mockDepsAppendBidderNames(t *testing.T, ex *mockExchangeAppendBidderNames) &mockVideoStoredReqFetcher{}, &mockVideoStoredReqFetcher{}, empty_fetcher.EmptyFetcher{}, - &config.Configuration{MaxRequestSize: maxSize}, + &config.Configuration{Video: config.Video{EnableDeprecatedEndpoint: true}, MaxRequestSize: maxSize}, &metricsConfig.NilMetricsEngine{}, analyticsBuild.New(&config.Analytics{}), map[string]string{}, @@ -1376,7 +1376,7 @@ func mockDepsNoBids(t *testing.T, ex *mockExchangeVideoNoBids) *endpointDeps { &mockVideoStoredReqFetcher{}, &mockVideoStoredReqFetcher{}, empty_fetcher.EmptyFetcher{}, - &config.Configuration{MaxRequestSize: maxSize}, + &config.Configuration{Video: config.Video{EnableDeprecatedEndpoint: true}, MaxRequestSize: maxSize}, &metricsConfig.NilMetricsEngine{}, analyticsBuild.New(&config.Analytics{}), map[string]string{}, @@ -1548,3 +1548,37 @@ func TestVideoRequestValidationFailed(t *testing.T) { assert.Equal(t, 500, recorder.Code, "Should catch error in request") assert.Equal(t, "Critical error while running the video endpoint: request.tmax must be nonnegative. Got -2", errorMessage, "Incorrect request validation message") } + +func TestVideoEndpointDisabled(t *testing.T) { + ex := &mockExchangeVideo{} + req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader("{}")) + recorder := httptest.NewRecorder() + + deps := &endpointDeps{ + fakeUUIDGenerator{}, + ex, + ortb.NewRequestValidator(openrtb_ext.BuildBidderMap(), map[string]string{}, mockBidderParamValidator{}), + &mockVideoStoredReqFetcher{}, + &mockVideoStoredReqFetcher{}, + &mockAccountFetcher{data: mockVideoAccountData}, + &config.Configuration{Video: config.Video{EnableDeprecatedEndpoint: false}, MaxRequestSize: maxSize}, + &metricsConfig.NilMetricsEngine{}, + analyticsBuild.New(&config.Analytics{}), + map[string]string{}, + false, + []byte{}, + openrtb_ext.BuildBidderMap(), + ex.cache, + regexp.MustCompile(`[<>]`), + hardcodedResponseIPValidator{response: true}, + empty_fetcher.EmptyFetcher{}, + hooks.EmptyPlanBuilder{}, + nil, + openrtb_ext.NormalizeBidderName, + } + + deps.VideoAuctionEndpoint(recorder, req, nil) + + assert.Equal(t, http.StatusNotImplemented, recorder.Code, "Expected 501 status code when video endpoint is disabled") + assert.Equal(t, "The video endpoint is deprecated and will be removed in 5.0. You may re-enable it via the host configuration setting video.enable_deprecated_endpoint", recorder.Body.String(), "Unexpected error message") +} From d21932f3724112b58d91f1e5ec7add1252ed6015 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:03:25 -0500 Subject: [PATCH 162/272] Adjust white label only error messages (#4690) --- config/bidderinfo.go | 6 +++--- config/bidderinfo_test.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/bidderinfo.go b/config/bidderinfo.go index d3873bf2e9..6adb2d2a07 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -464,17 +464,17 @@ func validateAliases(aliasBidderInfo BidderInfo, infos BidderInfos, bidderName s } if aliasBidderInfo.WhiteLabelOnly { - return fmt.Errorf("bidder: %s is an alias and cannot be set as white label only", bidderName) + return fmt.Errorf("bidder '%s' is an alias and cannot be set as white label only", bidderName) } parentBidder, parentBidderFound := infos[aliasBidderInfo.AliasOf] if !parentBidderFound { - return fmt.Errorf("bidder: %s not found for an alias: %s", aliasBidderInfo.AliasOf, bidderName) + return fmt.Errorf("alias '%s' references a nonexistent bidder '%s'", bidderName, aliasBidderInfo.AliasOf) } if len(parentBidder.AliasOf) > 0 { - return fmt.Errorf("bidder: %s cannot be an alias of an alias: %s", aliasBidderInfo.AliasOf, bidderName) + return fmt.Errorf("alias '%s' cannot reference another alias '%s'", bidderName, aliasBidderInfo.AliasOf) } return nil diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 8c251842c7..785b85bc6e 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -516,7 +516,7 @@ func TestProcessAliasBidderInfo(t *testing.T) { AliasOf: "bidderA", }, }, - expectedErr: errors.New("bidder: bidderA not found for an alias: bidderB"), + expectedErr: errors.New("alias 'bidderB' references a nonexistent bidder 'bidderA'"), }, { description: "bidder info not found for an alias", @@ -698,21 +698,21 @@ func TestValidateAliases(t *testing.T) { bidderName: "b", bidderInfo: BidderInfo{AliasOf: "nonexistent"}, bidderInfos: BidderInfos{}, - expectedErr: errors.New("bidder: nonexistent not found for an alias: b"), // does this make sense? should it be reversed? + expectedErr: errors.New("alias 'b' references a nonexistent bidder 'nonexistent'"), }, { name: "alias-of-alias", bidderName: "b", bidderInfo: BidderInfo{AliasOf: "a"}, bidderInfos: BidderInfos{"a": BidderInfo{AliasOf: "foo"}}, - expectedErr: errors.New("bidder: a cannot be an alias of an alias: b"), // does this make sense? should it be reversed? + expectedErr: errors.New("alias 'b' cannot reference another alias 'a'"), }, { name: "whitelabelonly", bidderName: "b", bidderInfo: BidderInfo{AliasOf: "a", WhiteLabelOnly: true}, bidderInfos: BidderInfos{"a": BidderInfo{}}, - expectedErr: errors.New("bidder: b is an alias and cannot be set as white label only"), + expectedErr: errors.New("bidder 'b' is an alias and cannot be set as white label only"), }, } From 8eee15c259e14d8a0ccbd2e9ac9373481fcbd188 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Mon, 23 Feb 2026 23:38:57 -0500 Subject: [PATCH 163/272] Drop supportCors user sync YAML config option (#4682) --- analytics/core.go | 5 +- config/bidderinfo.go | 9 ---- config/bidderinfo_test.go | 32 ----------- config/config_test.go | 4 -- .../test/bidder-info-valid/stroeerCore.yaml | 3 +- endpoints/cookie_sync.go | 15 +++--- endpoints/cookie_sync_test.go | 54 +++++++++---------- static/bidder-info/imds.yaml | 1 - static/bidder-info/orbidder.yaml | 1 - static/bidder-info/resetdigital.yaml | 1 - static/bidder-info/sparteo.yaml | 3 +- usersync/syncer.go | 12 ++--- usersync/syncer_test.go | 7 +-- usersync/syncersbuilder_test.go | 17 ++---- 14 files changed, 46 insertions(+), 118 deletions(-) diff --git a/analytics/core.go b/analytics/core.go index 25ff46c824..7f700774fd 100644 --- a/analytics/core.go +++ b/analytics/core.go @@ -82,9 +82,8 @@ type CookieSyncBidder struct { } type UsersyncInfo struct { - URL string `json:"url,omitempty"` - Type string `json:"type,omitempty"` - SupportCORS bool `json:"supportCORS,omitempty"` + URL string `json:"url,omitempty"` + Type string `json:"type,omitempty"` } // NotificationEvent object of a transaction at /event diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 6adb2d2a07..7ded01422c 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -127,9 +127,6 @@ type Syncer struct { // ExternalURL is available as a macro to the RedirectURL template. ExternalURL string `yaml:"externalUrl" mapstructure:"external_url"` - // SupportCORS identifies if CORS is supported for the user syncing endpoints. - SupportCORS *bool `yaml:"supportCors" mapstructure:"support_cors"` - // FormatOverride allows a bidder to override their callback type "b" for iframe, "i" for redirect FormatOverride string `yaml:"formatOverride" mapstructure:"format_override"` @@ -154,7 +151,6 @@ func (s *Syncer) Equal(other *Syncer) bool { s.IFrame.Equal(other.IFrame) && s.Redirect.Equal(other.Redirect) && s.ExternalURL == other.ExternalURL && - ptrutil.Equal(s.SupportCORS, other.SupportCORS) && s.FormatOverride == other.FormatOverride && ptrutil.Equal(s.Enabled, other.Enabled) && s.SkipWhen.Equal(other.SkipWhen) @@ -264,7 +260,6 @@ func (s *Syncer) Defined() bool { s.IFrame != nil || s.Redirect != nil || s.ExternalURL != "" || - s.SupportCORS != nil || s.FormatOverride != "" || s.SkipWhen != nil } @@ -805,10 +800,6 @@ func (s *Syncer) Override(original *Syncer) *Syncer { copy.ExternalURL = s.ExternalURL } - if s.SupportCORS != nil { - copy.SupportCORS = s.SupportCORS - } - return © } diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 785b85bc6e..5e01f1fc6d 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -73,7 +73,6 @@ aliasOf: bidderA func TestLoadBidderInfoFromDisk(t *testing.T) { // should appear in result in mixed case bidder := "stroeerCore" - trueValue := true adapterConfigs := make(map[string]Adapter) adapterConfigs[strings.ToLower(bidder)] = Adapter{} @@ -115,7 +114,6 @@ func TestLoadBidderInfoFromDisk(t *testing.T) { ExternalURL: "https://redirect.host", UserMacro: "#UID", }, - SupportCORS: &trueValue, }, }, } @@ -1402,11 +1400,6 @@ func TestBidderInfoValidationNegative(t *testing.T) { } func TestSyncerOverride(t *testing.T) { - var ( - trueValue = true - falseValue = false - ) - testCases := []struct { description string givenOriginal *Syncer @@ -1467,12 +1460,6 @@ func TestSyncerOverride(t *testing.T) { givenOverride: &Syncer{ExternalURL: "override"}, expected: &Syncer{ExternalURL: "override"}, }, - { - description: "Override SupportCORS", - givenOriginal: &Syncer{SupportCORS: &trueValue}, - givenOverride: &Syncer{SupportCORS: &falseValue}, - expected: &Syncer{SupportCORS: &falseValue}, - }, { description: "Override Partial - Other Fields Untouched", givenOriginal: &Syncer{Key: "originalKey", ExternalURL: "originalExternalURL"}, @@ -1715,18 +1702,6 @@ func TestSyncerEqual(t *testing.T) { }, expected: false, }, - { - name: "different-support-cors", - syncer1: &Syncer{ - Key: "key", - SupportCORS: ptrutil.ToPtr(true), - }, - syncer2: &Syncer{ - Key: "key", - SupportCORS: ptrutil.ToPtr(false), - }, - expected: false, - }, { name: "different-format-override", syncer1: &Syncer{ @@ -1782,7 +1757,6 @@ func TestSyncerEqual(t *testing.T) { UserMacro: "$UID", }, ExternalURL: "https://external.com", - SupportCORS: ptrutil.ToPtr(true), FormatOverride: "i", Enabled: ptrutil.ToPtr(true), SkipWhen: &SkipWhen{ @@ -1803,7 +1777,6 @@ func TestSyncerEqual(t *testing.T) { UserMacro: "$UID", }, ExternalURL: "https://external.com", - SupportCORS: ptrutil.ToPtr(true), FormatOverride: "i", Enabled: ptrutil.ToPtr(true), SkipWhen: &SkipWhen{ @@ -2073,11 +2046,6 @@ func TestSyncerDefined(t *testing.T) { givenSyncer: &Syncer{ExternalURL: "anyURL"}, expected: true, }, - { - name: "supportscors-only", - givenSyncer: &Syncer{SupportCORS: ptrutil.ToPtr(false)}, - expected: true, - }, { name: "formatoverride-only", givenSyncer: &Syncer{FormatOverride: "anyFormat"}, diff --git a/config/config_test.go b/config/config_test.go index c17226ded0..f310c99e8d 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1023,8 +1023,6 @@ func TestMigrateConfigFromEnv(t *testing.T) { } func TestUserSyncFromEnv(t *testing.T) { - truePtr := true - // setup env vars for testing if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL"); ok { defer os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", oldval) @@ -1061,11 +1059,9 @@ func TestUserSyncFromEnv(t *testing.T) { assert.Equal(t, "http://some.url/sync?redirect={{.RedirectURL}}", cfg.BidderInfos["bidder1"].Syncer.Redirect.URL) assert.Equal(t, "[UID]", cfg.BidderInfos["bidder1"].Syncer.Redirect.UserMacro) assert.Nil(t, cfg.BidderInfos["bidder1"].Syncer.IFrame) - assert.Equal(t, &truePtr, cfg.BidderInfos["bidder1"].Syncer.SupportCORS) assert.Equal(t, "http://somedifferent.url/sync?redirect={{.RedirectURL}}", cfg.BidderInfos["bidder2"].Syncer.IFrame.URL) assert.Nil(t, cfg.BidderInfos["bidder2"].Syncer.Redirect) - assert.Nil(t, cfg.BidderInfos["bidder2"].Syncer.SupportCORS) } func TestBidderInfoFromEnv(t *testing.T) { diff --git a/config/test/bidder-info-valid/stroeerCore.yaml b/config/test/bidder-info-valid/stroeerCore.yaml index ef95d2388a..47314187ba 100644 --- a/config/test/bidder-info-valid/stroeerCore.yaml +++ b/config/test/bidder-info-valid/stroeerCore.yaml @@ -27,5 +27,4 @@ userSync: url: "https://foo.com/sync?mode=redirect&r={{.RedirectURL}}" redirectUrl: "{{.ExternalURL}}/setuid/redirect" externalUrl: "https://redirect.host" - userMacro: "#UID" - supportCors: true \ No newline at end of file + userMacro: "#UID" \ No newline at end of file diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index a90bc6117d..6c71072e7c 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -466,9 +466,8 @@ func (c *cookieSyncEndpoint) handleResponse(w http.ResponseWriter, tf usersync.S BidderCode: syncerChoice.Bidder, NoCookie: true, UsersyncInfo: cookieSyncResponseSync{ - URL: sync.URL, - Type: string(sync.Type), - SupportCORS: sync.SupportCORS, + URL: sync.URL, + Type: string(sync.Type), }, }) } @@ -536,9 +535,8 @@ func mapBidderStatusToAnalytics(from []cookieSyncResponseBidder) []*analytics.Co BidderCode: b.BidderCode, NoCookie: b.NoCookie, UsersyncInfo: &analytics.UsersyncInfo{ - URL: b.UsersyncInfo.URL, - Type: b.UsersyncInfo.Type, - SupportCORS: b.UsersyncInfo.SupportCORS, + URL: b.UsersyncInfo.URL, + Type: b.UsersyncInfo.Type, }, } } @@ -604,9 +602,8 @@ type cookieSyncResponseBidder struct { } type cookieSyncResponseSync struct { - URL string `json:"url,omitempty"` - Type string `json:"type,omitempty"` - SupportCORS bool `json:"supportCORS,omitempty"` + URL string `json:"url,omitempty"` + Type string `json:"type,omitempty"` } type cookieSyncResponseDebug struct { diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index 6fc56f797b..208627ab8f 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -114,7 +114,7 @@ func TestNewCookieSyncEndpoint(t *testing.T) { func TestCookieSyncHandle(t *testing.T) { syncTypeExpected := []usersync.SyncType{usersync.SyncTypeIFrame, usersync.SyncTypeRedirect} - sync := usersync.Sync{URL: "aURL", Type: usersync.SyncTypeRedirect, SupportCORS: true} + sync := usersync.Sync{URL: "aURL", Type: usersync.SyncTypeRedirect} syncer := MockSyncer{} syncer.On("GetSync", syncTypeExpected, macros.UserSyncPrivacy{}).Return(sync, nil).Maybe() @@ -144,7 +144,7 @@ func TestCookieSyncHandle(t *testing.T) { }, expectedStatusCode: 200, expectedBody: `{"status":"ok","bidder_status":[` + - `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect","supportCORS":true}}` + + `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect"}}` + `]}` + "\n", setMetricsExpectations: func(m *metrics.MetricsEngineMock) { m.On("RecordCookieSync", metrics.CookieSyncOK).Once() @@ -158,7 +158,7 @@ func TestCookieSyncHandle(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect"}, }, }, } @@ -176,7 +176,7 @@ func TestCookieSyncHandle(t *testing.T) { }, expectedStatusCode: 200, expectedBody: `{"status":"no_cookie","bidder_status":[` + - `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect","supportCORS":true}}` + + `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect"}}` + `]}` + "\n", setMetricsExpectations: func(m *metrics.MetricsEngineMock) { m.On("RecordCookieSync", metrics.CookieSyncOK).Once() @@ -190,7 +190,7 @@ func TestCookieSyncHandle(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect"}, }, }, } @@ -277,7 +277,7 @@ func TestCookieSyncHandle(t *testing.T) { }, expectedStatusCode: 200, expectedBody: `{"status":"ok","bidder_status":[` + - `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect","supportCORS":true}}` + + `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect"}}` + `],"debug":[{"bidder":"a","error":"Already in sync"}]}` + "\n", setMetricsExpectations: func(m *metrics.MetricsEngineMock) { m.On("RecordCookieSync", metrics.CookieSyncOK).Once() @@ -291,7 +291,7 @@ func TestCookieSyncHandle(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect"}, }, }, } @@ -313,7 +313,7 @@ func TestCookieSyncHandle(t *testing.T) { expectedStatusCode: 200, expectedCookieDeprecationHeader: true, expectedBody: `{"status":"ok","bidder_status":[` + - `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect","supportCORS":true}}` + + `{"bidder":"a","no_cookie":true,"usersync":{"url":"aURL","type":"redirect"}}` + `]}` + "\n", setMetricsExpectations: func(m *metrics.MetricsEngineMock) { m.On("RecordCookieSync", metrics.CookieSyncOK).Once() @@ -327,7 +327,7 @@ func TestCookieSyncHandle(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "redirect"}, }, }, } @@ -1793,12 +1793,12 @@ func TestCookieSyncHandleResponse(t *testing.T) { privacyMacros := macros.UserSyncPrivacy{USPrivacy: "anyConsent"} // The & in the URL is necessary to test proper JSON encoding. - syncA := usersync.Sync{URL: "https://syncA.com/sync?a=1&b=2", Type: usersync.SyncTypeRedirect, SupportCORS: true} + syncA := usersync.Sync{URL: "https://syncA.com/sync?a=1&b=2", Type: usersync.SyncTypeRedirect} syncerA := MockSyncer{} syncerA.On("GetSync", syncTypeExpected, privacyMacros).Return(syncA, nil).Maybe() // The & in the URL is necessary to test proper JSON encoding. - syncB := usersync.Sync{URL: "https://syncB.com/sync?a=1&b=2", Type: usersync.SyncTypeRedirect, SupportCORS: false} + syncB := usersync.Sync{URL: "https://syncB.com/sync?a=1&b=2", Type: usersync.SyncTypeRedirect} syncerB := MockSyncer{} syncerB.On("GetSync", syncTypeExpected, privacyMacros).Return(syncB, nil).Maybe() @@ -1837,7 +1837,7 @@ func TestCookieSyncHandleResponse(t *testing.T) { givenCookieHasSyncs: true, givenSyncersChosen: []usersync.SyncerChoice{{Bidder: "foo", Syncer: &syncerA}}, expectedJSON: `{"status":"ok","bidder_status":[` + - `{"bidder":"foo","no_cookie":true,"usersync":{"url":"https://syncA.com/sync?a=1&b=2","type":"redirect","supportCORS":true}}` + + `{"bidder":"foo","no_cookie":true,"usersync":{"url":"https://syncA.com/sync?a=1&b=2","type":"redirect"}}` + `]}` + "\n", expectedAnalytics: analytics.CookieSyncObject{ Status: 200, @@ -1845,7 +1845,7 @@ func TestCookieSyncHandleResponse(t *testing.T) { { BidderCode: "foo", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncA.com/sync?a=1&b=2", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncA.com/sync?a=1&b=2", Type: "redirect"}, }, }, }, @@ -1855,7 +1855,7 @@ func TestCookieSyncHandleResponse(t *testing.T) { givenCookieHasSyncs: true, givenSyncersChosen: []usersync.SyncerChoice{{Bidder: "foo", Syncer: &syncerA}, {Bidder: "bar", Syncer: &syncerB}}, expectedJSON: `{"status":"ok","bidder_status":[` + - `{"bidder":"foo","no_cookie":true,"usersync":{"url":"https://syncA.com/sync?a=1&b=2","type":"redirect","supportCORS":true}},` + + `{"bidder":"foo","no_cookie":true,"usersync":{"url":"https://syncA.com/sync?a=1&b=2","type":"redirect"}},` + `{"bidder":"bar","no_cookie":true,"usersync":{"url":"https://syncB.com/sync?a=1&b=2","type":"redirect"}}` + `]}` + "\n", expectedAnalytics: analytics.CookieSyncObject{ @@ -1864,12 +1864,12 @@ func TestCookieSyncHandleResponse(t *testing.T) { { BidderCode: "foo", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncA.com/sync?a=1&b=2", Type: "redirect", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncA.com/sync?a=1&b=2", Type: "redirect"}, }, { BidderCode: "bar", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncB.com/sync?a=1&b=2", Type: "redirect", SupportCORS: false}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncB.com/sync?a=1&b=2", Type: "redirect"}, }, }, }, @@ -1887,7 +1887,7 @@ func TestCookieSyncHandleResponse(t *testing.T) { { BidderCode: "bar", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncB.com/sync?a=1&b=2", Type: "redirect", SupportCORS: false}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "https://syncB.com/sync?a=1&b=2", Type: "redirect"}, }, }, }, @@ -1956,14 +1956,14 @@ func TestMapBidderStatusToAnalytics(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: cookieSyncResponseSync{URL: "aURL", Type: "aType", SupportCORS: false}, + UsersyncInfo: cookieSyncResponseSync{URL: "aURL", Type: "aType"}, }, }, expected: []*analytics.CookieSyncBidder{ { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "aType", SupportCORS: false}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "aType"}, }, }, }, @@ -1973,24 +1973,24 @@ func TestMapBidderStatusToAnalytics(t *testing.T) { { BidderCode: "a", NoCookie: true, - UsersyncInfo: cookieSyncResponseSync{URL: "aURL", Type: "aType", SupportCORS: false}, + UsersyncInfo: cookieSyncResponseSync{URL: "aURL", Type: "aType"}, }, { BidderCode: "b", NoCookie: false, - UsersyncInfo: cookieSyncResponseSync{URL: "bURL", Type: "bType", SupportCORS: true}, + UsersyncInfo: cookieSyncResponseSync{URL: "bURL", Type: "bType"}, }, }, expected: []*analytics.CookieSyncBidder{ { BidderCode: "a", NoCookie: true, - UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "aType", SupportCORS: false}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "aURL", Type: "aType"}, }, { BidderCode: "b", NoCookie: false, - UsersyncInfo: &analytics.UsersyncInfo{URL: "bURL", Type: "bType", SupportCORS: true}, + UsersyncInfo: &analytics.UsersyncInfo{URL: "bURL", Type: "bType"}, }, }, }, @@ -2621,15 +2621,15 @@ func createAccountJSON(priorityGroups [][]string, defaultCoopSync *bool) json.Ra func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { // Setup test syncers syncerA := MockSyncer{} - syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect}, nil).Maybe() syncerA.On("Key").Return("appnexus").Maybe() syncerA.On("SupportsType", mock.Anything).Return(true).Maybe() syncerB := MockSyncer{} - syncerB.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderB.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerB.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderB.com", Type: usersync.SyncTypeRedirect}, nil).Maybe() syncerB.On("Key").Return("rubicon").Maybe() syncerB.On("SupportsType", mock.Anything).Return(true).Maybe() syncerC := MockSyncer{} - syncerC.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderC.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerC.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderC.com", Type: usersync.SyncTypeRedirect}, nil).Maybe() syncerC.On("Key").Return("pubmatic").Maybe() syncerC.On("SupportsType", mock.Anything).Return(true).Maybe() // Need to choose real bidder names because the standard chooser is hardcoded to validate against them @@ -2788,7 +2788,7 @@ func TestCookieSyncPriorityGroupsEdgeCases(t *testing.T) { // Setup basic syncers syncerA := MockSyncer{} syncerA.On("Key").Return("bidderA") - syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect, SupportCORS: false}, nil).Maybe() + syncerA.On("GetSync", mock.Anything, mock.Anything).Return(usersync.Sync{URL: "https://sync.bidderA.com", Type: usersync.SyncTypeRedirect}, nil).Maybe() syncerA.On("SupportsType", mock.Anything).Return(true).Maybe() syncersByBidder := map[string]usersync.Syncer{ diff --git a/static/bidder-info/imds.yaml b/static/bidder-info/imds.yaml index 135b67fc1f..73f2099548 100644 --- a/static/bidder-info/imds.yaml +++ b/static/bidder-info/imds.yaml @@ -15,7 +15,6 @@ capabilities: - banner - video userSync: - supportCors: true iframe: url: "https://ad-cdn.technoratimedia.com/html/usersync.html?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gppsid={{.GPPSID}}&cb={{.RedirectURL}}" userMacro: "[USER_ID]" diff --git a/static/bidder-info/orbidder.yaml b/static/bidder-info/orbidder.yaml index c42fb91de4..74348c75d7 100644 --- a/static/bidder-info/orbidder.yaml +++ b/static/bidder-info/orbidder.yaml @@ -11,7 +11,6 @@ capabilities: - banner - native userSync: - supportCors: true redirect: url: "https://orbidder.otto.de/pbs-usersync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&redirect={{.RedirectURL}}" userMacro: "[ODN_ID]" \ No newline at end of file diff --git a/static/bidder-info/resetdigital.yaml b/static/bidder-info/resetdigital.yaml index db85d114a3..0651791dc0 100644 --- a/static/bidder-info/resetdigital.yaml +++ b/static/bidder-info/resetdigital.yaml @@ -21,4 +21,3 @@ usersync: redirect: url: "https://sync.resetdigital.co/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" userMacro: "$UID" - supportCORS: true diff --git a/static/bidder-info/sparteo.yaml b/static/bidder-info/sparteo.yaml index 1ad61ab072..c1f862ed06 100644 --- a/static/bidder-info/sparteo.yaml +++ b/static/bidder-info/sparteo.yaml @@ -16,5 +16,4 @@ capabilities: endpoint: "https://bid.sparteo.com/s2s-auction" userSync: iframe: - url: "https://sync.sparteo.com/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect_url={{.RedirectURL}}" - supportCors: true \ No newline at end of file + url: "https://sync.sparteo.com/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect_url={{.RedirectURL}}" \ No newline at end of file diff --git a/usersync/syncer.go b/usersync/syncer.go index b2fec61610..b96b79cce2 100644 --- a/usersync/syncer.go +++ b/usersync/syncer.go @@ -39,9 +39,8 @@ type Syncer interface { // Sync represents a user sync to be performed by the user's device. type Sync struct { - URL string - Type SyncType - SupportCORS bool + URL string + Type SyncType } type standardSyncer struct { @@ -49,7 +48,6 @@ type standardSyncer struct { defaultSyncType SyncType iframe *template.Template redirect *template.Template - supportCORS bool formatOverride string } @@ -67,7 +65,6 @@ func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer, bidder st syncer := standardSyncer{ key: syncerConfig.Key, defaultSyncType: resolveDefaultSyncType(syncerConfig), - supportCORS: syncerConfig.SupportCORS != nil && *syncerConfig.SupportCORS, formatOverride: syncerConfig.FormatOverride, } @@ -237,9 +234,8 @@ func (s standardSyncer) GetSync(syncTypes []SyncType, userSyncMacros macros.User } sync := Sync{ - URL: url, - Type: syncType, - SupportCORS: s.supportCORS, + URL: url, + Type: syncType, } return sync, nil } diff --git a/usersync/syncer_test.go b/usersync/syncer_test.go index 020fb26df6..1670a3452e 100644 --- a/usersync/syncer_test.go +++ b/usersync/syncer_test.go @@ -11,7 +11,6 @@ import ( func TestNewSyncer(t *testing.T) { var ( - supportCORS = true hostConfig = config.UserSync{ExternalURL: "http://host.com", RedirectURL: "{{.ExternalURL}}/host"} macroValues = macros.UserSyncPrivacy{GDPR: "A", GDPRConsent: "B", USPrivacy: "C"} iframeConfig = &config.SyncerEndpoint{URL: "https://bidder.com/iframe?redirect={{.RedirectURL}}"} @@ -107,7 +106,6 @@ func TestNewSyncer(t *testing.T) { for _, test := range testCases { syncerConfig := config.Syncer{ Key: test.givenKey, - SupportCORS: &supportCORS, IFrame: test.givenIFrameConfig, Redirect: test.givenRedirectConfig, ExternalURL: test.givenExternalURL, @@ -120,7 +118,6 @@ func TestNewSyncer(t *testing.T) { if assert.IsType(t, standardSyncer{}, result, test.description+":result_type") { result := result.(standardSyncer) assert.Equal(t, test.givenKey, result.key, test.description+":key") - assert.Equal(t, supportCORS, result.supportCORS, test.description+":cors") assert.Equal(t, test.expectedDefault, result.defaultSyncType, test.description+":default_sync") if test.expectedIFrame == "" { @@ -682,14 +679,14 @@ func TestSyncerGetSync(t *testing.T) { givenSyncer: standardSyncer{iframe: iframeTemplate, redirect: redirectTemplate}, givenSyncTypes: []SyncType{SyncTypeIFrame}, givenMacros: macros.UserSyncPrivacy{GDPR: "A", GDPRConsent: "B", USPrivacy: "C"}, - expectedSync: Sync{URL: "iframe,gdpr:A,gdprconsent:B,ccpa:C", Type: SyncTypeIFrame, SupportCORS: false}, + expectedSync: Sync{URL: "iframe,gdpr:A,gdprconsent:B,ccpa:C", Type: SyncTypeIFrame}, }, { description: "Redirect", givenSyncer: standardSyncer{iframe: iframeTemplate, redirect: redirectTemplate}, givenSyncTypes: []SyncType{SyncTypeRedirect}, givenMacros: macros.UserSyncPrivacy{GDPR: "A", GDPRConsent: "B", USPrivacy: "C"}, - expectedSync: Sync{URL: "redirect,gdpr:A,gdprconsent:B,ccpa:C", Type: SyncTypeRedirect, SupportCORS: false}, + expectedSync: Sync{URL: "redirect,gdpr:A,gdprconsent:B,ccpa:C", Type: SyncTypeRedirect}, }, { description: "Macro Error", diff --git a/usersync/syncersbuilder_test.go b/usersync/syncersbuilder_test.go index a08df08172..f86808a21f 100644 --- a/usersync/syncersbuilder_test.go +++ b/usersync/syncersbuilder_test.go @@ -192,7 +192,6 @@ func TestShouldCreateSyncer(t *testing.T) { var ( anySupports = []string{"iframe"} anyEndpoint = &config.SyncerEndpoint{} - anyCORS = true ) testCases := []struct { @@ -212,7 +211,7 @@ func TestShouldCreateSyncer(t *testing.T) { }, { description: "Enabled, Syncer - Fully Loaded", - given: config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}}, + given: config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint}}, expected: true, }, { @@ -235,11 +234,6 @@ func TestShouldCreateSyncer(t *testing.T) { given: config.BidderInfo{Disabled: false, Syncer: &config.Syncer{Redirect: anyEndpoint}}, expected: true, }, - { - description: "Enabled, Syncer - Only SupportCORS", - given: config.BidderInfo{Disabled: false, Syncer: &config.Syncer{SupportCORS: &anyCORS}}, - expected: true, - }, { description: "Disabled, No Syncer", given: config.BidderInfo{Disabled: true, Syncer: nil}, @@ -252,7 +246,7 @@ func TestShouldCreateSyncer(t *testing.T) { }, { description: "Disabled, Syncer - Fully Loaded", - given: config.BidderInfo{Disabled: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}}, + given: config.BidderInfo{Disabled: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint}}, expected: false, }, { @@ -275,11 +269,6 @@ func TestShouldCreateSyncer(t *testing.T) { given: config.BidderInfo{Disabled: true, Syncer: &config.Syncer{Redirect: anyEndpoint}}, expected: false, }, - { - description: "Disabled, Syncer - Only SupportCORS", - given: config.BidderInfo{Disabled: true, Syncer: &config.Syncer{SupportCORS: &anyCORS}}, - expected: false, - }, { description: "WhiteLabelOnly, No Syncer", given: config.BidderInfo{WhiteLabelOnly: true, Syncer: nil}, @@ -292,7 +281,7 @@ func TestShouldCreateSyncer(t *testing.T) { }, { description: "WhiteLabelOnly, Syncer - Fully Loaded", - given: config.BidderInfo{WhiteLabelOnly: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}}, + given: config.BidderInfo{WhiteLabelOnly: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint}}, expected: false, }, } From 2e132395a87df50e9281e1f1fd815b1050d3ad10 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Tue, 24 Feb 2026 09:53:54 -0500 Subject: [PATCH 164/272] Add removed bidder warnings (#4692) --- exchange/adapter_util.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 27e36a0705..377130118e 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -127,6 +127,10 @@ func GetDisabledBidderWarningMessages(infos config.BidderInfos) map[string]strin "bizzclick": `Bidder "bizzclick" is no longer available in Prebid Server. Please update your configuration. "bizzclick" has been renamed to "blasto".`, "liftoff": `Bidder "liftoff" is no longer available in Prebid Server. If you're looking to use the Vungle Exchange adapter, please rename it to "vungle" in your configuration.`, "gothamads": `Bidder "gothamads" is no longer available in Prebid Server. Please rename it to "intenze" in your configuration.`, + "adocean": `Bidder "adocean" is no longer available in Prebid Server. Please update your configuration.`, + "dxkulture": `Bidder "dxkulture" is no longer available in Prebid Server. Please update your configuration.`, + "mobupps": `Bidder "mobupps" is no longer available in Prebid Server. Please update your configuration.`, + "vimayx": `Bidder "vimayx" is no longer available in Prebid Server. Please update your configuration.`, } return mergeRemovedAndDisabledBidderWarningMessages(removed, infos) From c756d445c55808cd1e662e1b318d10e2fa26a23c Mon Sep 17 00:00:00 2001 From: Jaime Moncayo <jaime.moncayo@kargo.com> Date: Tue, 24 Feb 2026 09:17:26 -0600 Subject: [PATCH 165/272] Kargo: Update endpoint (#4667) Co-authored-by: Nick Llerandi <nick.llerandi@kargo.com> Co-authored-by: Shane Lacey <shanel262@hotmail.com> --- static/bidder-info/kargo.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/kargo.yaml b/static/bidder-info/kargo.yaml index 6acd679ebc..accbf1a3fc 100644 --- a/static/bidder-info/kargo.yaml +++ b/static/bidder-info/kargo.yaml @@ -1,4 +1,4 @@ -endpoint: "https://krk.kargo.com/api/v1/openrtb" +endpoint: "https://krk2.kargo.com/api/v1/openrtb" maintainer: email: "kraken@kargo.com" gvlVendorID: 972 From ec0c87ab1757f60d698ae2d897287663c8bd4658 Mon Sep 17 00:00:00 2001 From: dev-adverxo <developer@adverxo.com> Date: Wed, 25 Feb 2026 00:37:49 +0100 Subject: [PATCH 166/272] New Adapter: Alchemyx - Adverxo Alias (#4663) Co-authored-by: Abraham <abraham@kimiagroup.com> --- static/bidder-info/alchemyx.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 static/bidder-info/alchemyx.yaml diff --git a/static/bidder-info/alchemyx.yaml b/static/bidder-info/alchemyx.yaml new file mode 100644 index 0000000000..2758dd6249 --- /dev/null +++ b/static/bidder-info/alchemyx.yaml @@ -0,0 +1,11 @@ +endpoint: "https://alchemyx.live/auction?id={{.AdUnit}}&auth={{.TokenID}}" +aliasOf: "adverxo" +maintainer: + email: "prebid@alchemyx.io" +userSync: + iframe: + url: https://alchemyx.online/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://alchemyx.online/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID From bcbcc0a4012a36621e8c8fd458be2acb8871d924 Mon Sep 17 00:00:00 2001 From: ysfbsf <youssef.bsf@gmail.com> Date: Wed, 25 Feb 2026 01:18:34 +0000 Subject: [PATCH 167/272] Missena: Update parameters and add versioning support (#4557) --- adapters/missena/missena.go | 51 +++-- .../exemplary/bid-floor-currency.json | 4 +- .../missenatest/exemplary/multiple-imps.json | 7 +- .../exemplary/simple-banner-ipv6.json | 7 +- .../exemplary/simple-banner-with-eids.json | 194 ++++++++++++++++++ .../exemplary/simple-banner-with-sample.json | 137 +++++++++++++ .../missenatest/exemplary/simple-banner.json | 4 +- .../exemplary/valid-imp-error-imp.json | 7 +- .../missenatest/supplemental/status-204.json | 7 +- .../missenatest/supplemental/status-400.json | 4 +- .../supplemental/status-not-200.json | 7 +- adapters/missena/params_test.go | 6 +- openrtb_ext/imp_missena.go | 2 +- static/bidder-params/missena.json | 4 +- 14 files changed, 402 insertions(+), 39 deletions(-) create mode 100644 adapters/missena/missenatest/exemplary/simple-banner-with-eids.json create mode 100644 adapters/missena/missenatest/exemplary/simple-banner-with-sample.json diff --git a/adapters/missena/missena.go b/adapters/missena/missena.go index 401f11d159..ae51ec6274 100644 --- a/adapters/missena/missena.go +++ b/adapters/missena/missena.go @@ -24,6 +24,7 @@ type MissenaAdRequest struct { Adunit string `json:"adunit,omitempty"` BuyerUID string `json:"buyeruid,omitempty"` Currency string `json:"currency,omitempty"` + Debug bool `json:"debug,omitempty"` EIDs []openrtb2.EID `json:"userEids,omitempty"` Floor float64 `json:"floor,omitempty"` FloorCurrency string `json:"floor_currency,omitempty"` @@ -43,19 +44,19 @@ type BidServerResponse struct { } type UserParams struct { + APIKey string `json:"apiKey,omitempty"` Formats []string `json:"formats,omitempty"` Placement string `json:"placement,omitempty" default:"sticky"` - TestMode string `json:"test,omitempty"` + Sample string `json:"sample,omitempty"` Settings map[string]any `json:"settings,omitempty"` } -type MissenaAdapter struct { - EndpointTemplate *template.Template -} - -var defaultCur = "USD" +const ( + currencyUSD = "USD" + currencyEUR = "EUR" +) -// Builder builds a new instance of the Foo adapter for the given bidder with the given config. +// Builder builds a new instance of the Missena adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { endpoint, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { @@ -67,18 +68,25 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co return bidder, nil } +func getVersionString() string { + if version.Ver == "" { + return version.VerUnknown + } + return version.Ver +} + func getCurrency(currencies []string) (string, error) { eurAvailable := false for _, cur := range currencies { - if cur == defaultCur { - return defaultCur, nil + if cur == currencyUSD { + return currencyUSD, nil } - if cur == "EUR" { + if cur == currencyEUR { eurAvailable = true } } if eurAvailable { - return "EUR", nil + return currencyEUR, nil } return "", fmt.Errorf("no currency supported %v", currencies) } @@ -97,7 +105,7 @@ func (a *adapter) makeRequest(imp openrtb2.Imp, request *openrtb2.BidRequest, re } cur, err := getCurrency(request.Cur) if err != nil { - cur = defaultCur + cur = currencyUSD } var floor float64 @@ -106,7 +114,7 @@ func (a *adapter) makeRequest(imp openrtb2.Imp, request *openrtb2.BidRequest, re floor = imp.BidFloor floorCur, err = getCurrency(request.Cur) if err != nil { - floorCur = defaultCur + floorCur = currencyUSD floor, err = requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, floorCur) if err != nil { return nil, err @@ -114,9 +122,20 @@ func (a *adapter) makeRequest(imp openrtb2.Imp, request *openrtb2.BidRequest, re } } + // Extract EIDs from user.ext. Unmarshal errors are intentionally ignored + // to allow requests to proceed without EIDs, as they are optional. + var eids []openrtb2.EID + if request.User != nil && request.User.Ext != nil { + var extUser openrtb_ext.ExtUser + if err := jsonutil.Unmarshal(request.User.Ext, &extUser); err == nil { + eids = extUser.Eids + } + } + missenaRequest := MissenaAdRequest{ Adunit: imp.ID, Currency: cur, + Debug: request.Test == 1, Floor: floor, FloorCurrency: floorCur, IdempotencyKey: request.ID, @@ -124,12 +143,14 @@ func (a *adapter) makeRequest(imp openrtb2.Imp, request *openrtb2.BidRequest, re RequestID: request.ID, Timeout: request.TMax, UserParams: UserParams{ + APIKey: params.APIKey, Formats: params.Formats, Placement: params.Placement, - TestMode: params.TestMode, + Sample: params.Sample, Settings: params.Settings, }, - Version: version.Ver, + EIDs: eids, + Version: fmt.Sprintf("prebid-server@%s", getVersionString()), } body, err := jsonutil.Marshal(missenaRequest) diff --git a/adapters/missena/missenatest/exemplary/bid-floor-currency.json b/adapters/missena/missenatest/exemplary/bid-floor-currency.json index 940a2451d8..a2601c35bf 100644 --- a/adapters/missena/missenatest/exemplary/bid-floor-currency.json +++ b/adapters/missena/missenatest/exemplary/bid-floor-currency.json @@ -88,9 +88,11 @@ "request_id": "test-request-id", "timeout": 500, "params": { + "apiKey": "test-api-key", "formats": ["banner"], "placement": "sticky" - } + }, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/missenatest/exemplary/multiple-imps.json b/adapters/missena/missenatest/exemplary/multiple-imps.json index 9f0ea74ce3..2dadd0fee0 100644 --- a/adapters/missena/missenatest/exemplary/multiple-imps.json +++ b/adapters/missena/missenatest/exemplary/multiple-imps.json @@ -144,11 +144,12 @@ } }, "params": { - "placement": "test-placement-1", - "test": "1" + "apiKey": "test-api-key", + "placement": "test-placement-1" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id-1"] }, diff --git a/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json b/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json index ab279f26b7..3d04e6738a 100644 --- a/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json +++ b/adapters/missena/missenatest/exemplary/simple-banner-ipv6.json @@ -96,11 +96,12 @@ } }, "params": { - "placement": "test-placement", - "test": "1" + "apiKey": "test-api-key", + "placement": "test-placement" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/missenatest/exemplary/simple-banner-with-eids.json b/adapters/missena/missenatest/exemplary/simple-banner-with-eids.json new file mode 100644 index 0000000000..ef3495317f --- /dev/null +++ b/adapters/missena/missenatest/exemplary/simple-banner-with-eids.json @@ -0,0 +1,194 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "tmax": 500, + "at": 1, + "cur": ["EUR"], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA", + "eids": [ + { + "source": "adserver.org", + "uids": [ + { + "id": "111111111111", + "atype": 1 + } + ] + }, + { + "source": "liveramp.com", + "uids": [ + { + "id": "AjfowMv4ZHZQME1RWTn", + "atype": 3 + } + ] + } + ] + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "site": { + "page": "https://example.com/page", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?t=test-api-key", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"], + "X-Forwarded-For": ["123.123.123.123"], + "Referer": ["https://example.com/page"], + "Origin": ["https://example.com"] + }, + "body": { + "adunit": "test-imp-id", + "currency": "EUR", + "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA", + "eids": [ + { + "source": "adserver.org", + "uids": [ + { + "id": "111111111111", + "atype": 1 + } + ] + }, + { + "source": "liveramp.com", + "uids": [ + { + "id": "AjfowMv4ZHZQME1RWTn", + "atype": 3 + } + ] + } + ] + } + } + }, + "params": { + "apiKey": "test-api-key", + "placement": "test-placement" + }, + "request_id": "test-request-id", + "timeout": 500, + "userEids": [ + { + "source": "adserver.org", + "uids": [ + { + "id": "111111111111", + "atype": 1 + } + ] + }, + { + "source": "liveramp.com", + "uids": [ + { + "id": "AjfowMv4ZHZQME1RWTn", + "atype": 3 + } + ] + } + ], + "version": "prebid-server@unknown" + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "ad": "<div>test ad</div>", + "cpm": 1.5, + "currency": "EUR", + "requestId": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-request-id" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/missena/missenatest/exemplary/simple-banner-with-sample.json b/adapters/missena/missenatest/exemplary/simple-banner-with-sample.json new file mode 100644 index 0000000000..4406bf98b2 --- /dev/null +++ b/adapters/missena/missenatest/exemplary/simple-banner-with-sample.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "tmax": 500, + "at": 1, + "cur": ["EUR"], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "site": { + "page": "https://example.com/page", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement", + "sample": "test-sample-value" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?t=test-api-key", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"], + "X-Forwarded-For": ["123.123.123.123"], + "Referer": ["https://example.com/page"], + "Origin": ["https://example.com"] + }, + "body": { + "adunit": "test-imp-id", + "currency": "EUR", + "ik": "test-request-id", + "ortb2": { + "at": 1, + "cur": ["EUR"], + "device": { + "ip": "123.123.123.123", + "ua": "test-user-agent" + }, + "id": "test-request-id", + "imp": [ + { + "banner": { + "h": 50, + "w": 320 + }, + "ext": { + "bidder": { + "apiKey": "test-api-key", + "placement": "test-placement", + "sample": "test-sample-value" + } + }, + "id": "test-imp-id" + } + ], + "regs": { + "ext": { + "gdpr": 1 + } + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "tmax": 500, + "user": { + "ext": { + "consent": "CO-X2XiO_eyUoAsAxBFRBECsA" + } + } + }, + "params": { + "apiKey": "test-api-key", + "placement": "test-placement", + "sample": "test-sample-value" + }, + "request_id": "test-request-id", + "timeout": 500, + "version": "prebid-server@unknown" + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "ad": "<div>test ad</div>", + "cpm": 1.5, + "currency": "EUR", + "requestId": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-request-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test ad</div>", + "crid": "test-request-id" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/missena/missenatest/exemplary/simple-banner.json b/adapters/missena/missenatest/exemplary/simple-banner.json index e2368579b5..543f0c4995 100644 --- a/adapters/missena/missenatest/exemplary/simple-banner.json +++ b/adapters/missena/missenatest/exemplary/simple-banner.json @@ -94,10 +94,12 @@ } }, "params": { + "apiKey": "test-api-key", "placement": "test-placement" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json b/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json index 9f0ea74ce3..2dadd0fee0 100644 --- a/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json +++ b/adapters/missena/missenatest/exemplary/valid-imp-error-imp.json @@ -144,11 +144,12 @@ } }, "params": { - "placement": "test-placement-1", - "test": "1" + "apiKey": "test-api-key", + "placement": "test-placement-1" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id-1"] }, diff --git a/adapters/missena/missenatest/supplemental/status-204.json b/adapters/missena/missenatest/supplemental/status-204.json index 4cd1a24b8a..ab649bb814 100644 --- a/adapters/missena/missenatest/supplemental/status-204.json +++ b/adapters/missena/missenatest/supplemental/status-204.json @@ -96,11 +96,12 @@ } }, "params": { - "placement": "test-placement", - "test": "1" + "apiKey": "test-api-key", + "placement": "test-placement" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/missenatest/supplemental/status-400.json b/adapters/missena/missenatest/supplemental/status-400.json index 616fa05cab..8b0dbf6d77 100644 --- a/adapters/missena/missenatest/supplemental/status-400.json +++ b/adapters/missena/missenatest/supplemental/status-400.json @@ -94,10 +94,12 @@ } }, "params": { + "apiKey": "test-api-key", "placement": "test-placement" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/missenatest/supplemental/status-not-200.json b/adapters/missena/missenatest/supplemental/status-not-200.json index 3dc28ab762..600ae11f62 100644 --- a/adapters/missena/missenatest/supplemental/status-not-200.json +++ b/adapters/missena/missenatest/supplemental/status-not-200.json @@ -96,11 +96,12 @@ } }, "params": { - "placement": "test-placement", - "test": "1" + "apiKey": "test-api-key", + "placement": "test-placement" }, "request_id": "test-request-id", - "timeout": 500 + "timeout": 500, + "version": "prebid-server@unknown" }, "impIDs": ["test-imp-id"] }, diff --git a/adapters/missena/params_test.go b/adapters/missena/params_test.go index 393561b43c..91eca91f92 100644 --- a/adapters/missena/params_test.go +++ b/adapters/missena/params_test.go @@ -36,7 +36,7 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"apiKey": "PA-123456"}`, `{"apiKey": "PA-123456", "placement": "sticky"}`, - `{"apiKey": "PA-123456", "test": "native"}`, + `{"apiKey": "PA-123456", "sample": "test-sample"}`, } var invalidParams = []string{ @@ -45,6 +45,6 @@ var invalidParams = []string{ `{"placement": 111}`, `{"placement": "sticky"}`, `{"apiKey": "PA-123456", "placement": 111}`, - `{"test": "native"}`, - `{"apiKey": "PA-123456", "test": 111}`, + `{"sample": "test-sample"}`, + `{"apiKey": "PA-123456", "sample": 111}`, } diff --git a/openrtb_ext/imp_missena.go b/openrtb_ext/imp_missena.go index 6884209b7f..ac4a722341 100644 --- a/openrtb_ext/imp_missena.go +++ b/openrtb_ext/imp_missena.go @@ -4,6 +4,6 @@ type ExtImpMissena struct { APIKey string `json:"apiKey"` Formats []string `json:"formats"` Placement string `json:"placement"` - TestMode string `json:"test"` + Sample string `json:"sample"` Settings map[string]any `json:"settings,omitempty"` } diff --git a/static/bidder-params/missena.json b/static/bidder-params/missena.json index f06b9cf466..9e17a07f08 100644 --- a/static/bidder-params/missena.json +++ b/static/bidder-params/missena.json @@ -13,9 +13,9 @@ "type": "string", "description": "Placement Type (Sticky, Header, ...)" }, - "test": { + "sample": { "type": "string", - "description": "Test Mode" + "description": "Sample" }, "formats": { "type": "array", From 24e2245f59a45d68504472cf078d8c906eb6742d Mon Sep 17 00:00:00 2001 From: Daniel Baud <52867769+danielbaud@users.noreply.github.com> Date: Wed, 25 Feb 2026 02:53:27 +0100 Subject: [PATCH 168/272] New Adapter: Alliance Gravity (#4522) --- adapters/alliance_gravity/alliance_gravity.go | 181 +++++++++++++++ .../alliance_gravity/alliance_gravity_test.go | 20 ++ .../exemplary/simple-audio.json | 133 +++++++++++ .../exemplary/simple-banner-inapp.json | 139 ++++++++++++ .../simple-banner-multiple-bids.json | 213 ++++++++++++++++++ .../exemplary/simple-banner-with-uid.json | 152 +++++++++++++ .../exemplary/simple-banner.json | 107 +++++++++ .../exemplary/simple-multi-type-banner.json | 153 +++++++++++++ .../exemplary/simple-multi-type-video.json | 153 +++++++++++++ .../exemplary/simple-native.json | 122 ++++++++++ .../exemplary/simple-video.json | 137 +++++++++++ .../supplemental/204-response.json | 126 +++++++++++ .../supplemental/400-response.json | 132 +++++++++++ .../supplemental/500-response.json | 132 +++++++++++ .../supplemental/empty_seatbid.json | 130 +++++++++++ .../supplemental/ext.json | 33 +++ .../supplemental/invalid-bid-response.json | 66 ++++++ .../supplemental/wrong-payload.json | 74 ++++++ adapters/alliance_gravity/params_test.go | 48 ++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_alliance_gravity.go | 5 + static/bidder-info/alliance_gravity.yaml | 24 ++ static/bidder-params/alliance_gravity.json | 15 ++ 24 files changed, 2299 insertions(+) create mode 100644 adapters/alliance_gravity/alliance_gravity.go create mode 100644 adapters/alliance_gravity/alliance_gravity_test.go create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-audio.json create mode 100755 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-inapp.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-multiple-bids.json create mode 100755 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-with-uid.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-banner.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-video.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-native.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-video.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/204-response.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/400-response.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/500-response.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/empty_seatbid.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/ext.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/invalid-bid-response.json create mode 100644 adapters/alliance_gravity/alliance_gravitytest/supplemental/wrong-payload.json create mode 100644 adapters/alliance_gravity/params_test.go create mode 100644 openrtb_ext/imp_alliance_gravity.go create mode 100644 static/bidder-info/alliance_gravity.yaml create mode 100644 static/bidder-params/alliance_gravity.json diff --git a/adapters/alliance_gravity/alliance_gravity.go b/adapters/alliance_gravity/alliance_gravity.go new file mode 100644 index 0000000000..a79a759140 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravity.go @@ -0,0 +1,181 @@ +package alliance_gravity + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func generateImps(imps []openrtb2.Imp) ([]openrtb2.Imp, error) { + var generatedImps []openrtb2.Imp + for _, imp := range imps { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: err.Error(), + } + } + + var allianceGravityExt openrtb_ext.ExtImpAllianceGravity + if err := jsonutil.Unmarshal(bidderExt.Bidder, &allianceGravityExt); err != nil { + return nil, &errortypes.BadInput{ + Message: err.Error(), + } + } + + bidderExt.Bidder = json.RawMessage(`{}`) + bidderExt.Prebid = &openrtb_ext.ExtImpPrebid{ + StoredRequest: &openrtb_ext.ExtStoredRequest{ + ID: allianceGravityExt.SrId, + }, + } + + bidderExtJSON, err := jsonutil.Marshal(bidderExt) + if err != nil { + return nil, &errortypes.BadInput{ + Message: err.Error(), + } + } + + impCopy := imp + impCopy.Ext = bidderExtJSON + + generatedImps = append(generatedImps, impCopy) + } + return generatedImps, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var generatedImps, err = generateImps(request.Imp) + if err != nil { + return nil, []error{err} + } + + request.Imp = generatedImps + + requestJSON, err := jsonutil.Marshal(request) + + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + if request.Device != nil { + if request.Device.UA != "" { + headers.Add("User-Agent", request.Device.UA) + } + if request.Device.IP != "" { + headers.Add("X-Forwarded-For", request.Device.IP) + } else if request.Device.IPv6 != "" { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + } + if request.Site != nil { + if request.Site.Page != "" { + headers.Add("Referer", request.Site.Page) + } + } + + if request.User != nil && request.User.BuyerUID != "" { + headers.Add("Cookie", "uids="+request.User.BuyerUID) + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if responseData.StatusCode == http.StatusNoContent { + return nil, nil + } + + if responseData.StatusCode == http.StatusBadRequest { + err := &errortypes.BadInput{ + Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", + } + return nil, []error{err} + } + + if responseData.StatusCode != http.StatusOK { + err := &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + var bids []*adapters.TypedBid + var errors []error + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bids = append(bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + + if len(bids) == 0 { + return nil, nil + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bids)) + + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + bidResponse.Bids = bids + + return bidResponse, errors +} + +func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil && bidExt.Prebid != nil { + return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) + } + } + + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID), + } +} diff --git a/adapters/alliance_gravity/alliance_gravity_test.go b/adapters/alliance_gravity/alliance_gravity_test.go new file mode 100644 index 0000000000..1a5adcc64b --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravity_test.go @@ -0,0 +1,20 @@ +package alliance_gravity + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAllianceGravity, config.Adapter{ + Endpoint: "http://endpoint"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "alliance_gravitytest", bidder) +} diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-audio.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-audio.json new file mode 100644 index 0000000000..e0aad7ec9d --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-audio.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "audio": { + "mimes": ["audio/mp3"], + "protocols": [2, 5], + "minduration": 10, + "maxduration": 30 + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "audio": { + "mimes": ["audio/mp3"], + "protocols": [2, 5], + "minduration": 10, + "maxduration": 30 + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs": ["imp-id-123"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "ext": { + "prebid": { + "type": "audio" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "ext": { + "prebid": { + "type": "audio" + } + } + }, + "type": "audio" + } + ] + } + ] +} + diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-inapp.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-inapp.json new file mode 100755 index 0000000000..7748fbf6f6 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-inapp.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs": [ + "imp-id-123" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<h1>test ad</h1>", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<h1>test ad</h1>", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-multiple-bids.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-multiple-bids.json new file mode 100644 index 0000000000..db68c93272 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-multiple-bids.json @@ -0,0 +1,213 @@ +{ + "mockBidRequest": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "srid": "abc" + } + } + }, + { + "id": "imp-id-456", + "banner": { + "format": [ + { + "w": 160, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "srid": "def" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "abc" + } + } + } + }, + { + "id": "imp-id-456", + "banner": { + "format": [ + { + "w": 160, + "h": 600 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "def" + } + } + } + } + ] + }, + "impIDs": [ + "imp-id-123", + "imp-id-456" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<div>Test Ad</div>", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + }, + { + "bid": [ + { + "id": "test-slot-id2", + "impid": "imp-id-1232", + "price": 0.5, + "crid": "creative-123", + "adm": "<div>Test Ad</div>", + "w": 160, + "h": 600, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<div>Test Ad</div>", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "test-slot-id2", + "impid": "imp-id-1232", + "price": 0.5, + "crid": "creative-123", + "adm": "<div>Test Ad</div>", + "w": 160, + "h": 600, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-with-uid.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-with-uid.json new file mode 100755 index 0000000000..ffee3a656e --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner-with-uid.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "user": { + "buyeruid": "grvt-id" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "Cookie": [ + "uids=grvt-id" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "user": { + "buyeruid": "grvt-id" + }, + "imp": [ + { + "id": "imp-id-123", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs": [ + "imp-id-123" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "test-ad", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "test-ad", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner.json new file mode 100644 index 0000000000..55b2dc5183 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-banner.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-id-123", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ], + "site": {} + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id":"imp-id-123", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ], + "site": {} + }, + "impIDs":["imp-id-123"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "EUR", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "imp-id-123", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "prebid": { + "type": "banner" + } + } + }] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "imp-id-123", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-banner.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-banner.json new file mode 100644 index 0000000000..b51482b54d --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-banner.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs":["imp-id-123"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<h1>test ad</h1>", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "<h1>test ad</h1>", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} + diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-video.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-video.json new file mode 100644 index 0000000000..6b382ede2d --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-multi-type-video.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs":["imp-id-123"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} + diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-native.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-native.json new file mode 100644 index 0000000000..ca9dc94649 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-native.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://good.site/url" + }, + "imp": [ + { + "id": "imp-id-123", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "https://good.site/url" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "https://good.site/url" + }, + "imp": [ + { + "id": "imp-id-123", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs": [ + "imp-id-123" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "EUR", + "seatbid": [ + { + "seat": "grid", + "bid": [ + { + "id": "randomid", + "impid": "imp-id-123", + "price": 0.5, + "adid": "12345678", + "adm": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}", + "ext": { + "prebid": { + "type": "native" + } + }, + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "imp-id-123", + "price": 0.5, + "adm": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}", + "adid": "12345678", + "cid": "987", + "crid": "12345678", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-video.json b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-video.json new file mode 100644 index 0000000000..cffc45e5f8 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/exemplary/simple-video.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "srid": "12341234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "criteo.com" + ], + "User-Agent": [ + "random user agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "criteo.com" + }, + "device": { + "os": "android", + "ip": "1.2.3.4", + "ua": "random user agent" + }, + "imp": [ + { + "id": "imp-id-123", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "12341234" + } + } + } + } + ] + }, + "impIDs":["imp-id-123"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "EUR", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "imp-id-123", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} + diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/204-response.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/204-response.json new file mode 100644 index 0000000000..b61adcc7a3 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/204-response.json @@ -0,0 +1,126 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "srid": "abcdefgh" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ], + "Cookie": [ + "uids=awesome-user" + ] + }, + "uri": "http://endpoint", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "abcdefgh" + } + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/400-response.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/400-response.json new file mode 100644 index 0000000000..15df859102 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/400-response.json @@ -0,0 +1,132 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "srid": "abcdefgh" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ], + "Cookie": [ + "uids=awesome-user" + ] + }, + "uri": "http://endpoint", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "abcdefgh" + } + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/500-response.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/500-response.json new file mode 100644 index 0000000000..adde21aeac --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/500-response.json @@ -0,0 +1,132 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "srid": "abcdefgh" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ], + "Cookie": [ + "uids=awesome-user" + ] + }, + "uri": "http://endpoint", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "abcdefgh" + } + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info.", + "comparison": "literal" + } + ] +} diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/empty_seatbid.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/empty_seatbid.json new file mode 100644 index 0000000000..3db49b75d9 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/empty_seatbid.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "srid": "abcdefgh" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ], + "Cookie": [ + "uids=awesome-user" + ] + }, + "uri": "http://endpoint", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "ogTAGID", + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "abcdefgh" + } + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/ext.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/ext.json new file mode 100644 index 0000000000..6858423661 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/ext.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "id": "testid", + "imp": [ + { + "id": "testimpid", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + }, + { + "w": 320, + "h": 300 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "placement_id": "1265" + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ] +} diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/invalid-bid-response.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/invalid-bid-response.json new file mode 100644 index 0000000000..bb6aeaf44c --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/invalid-bid-response.json @@ -0,0 +1,66 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "srid": "1234" + } + } + } + ], + "site": {} + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "1234" + } + } + } + } + ], + "site": {} + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": {}, + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "cannot unmarshal openrtb2.BidResponse.SeatBid: decode slice: expect [ or n, but found {", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/alliance_gravity/alliance_gravitytest/supplemental/wrong-payload.json b/adapters/alliance_gravity/alliance_gravitytest/supplemental/wrong-payload.json new file mode 100644 index 0000000000..cac99ad7b9 --- /dev/null +++ b/adapters/alliance_gravity/alliance_gravitytest/supplemental/wrong-payload.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "srid": "1234" + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://endpoint", + "body": { + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": {}, + "prebid": { + "storedrequest": { + "id": "1234" + } + } + } + } + ], + "site": {} + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/alliance_gravity/params_test.go b/adapters/alliance_gravity/params_test.go new file mode 100644 index 0000000000..c81fdf48e7 --- /dev/null +++ b/adapters/alliance_gravity/params_test.go @@ -0,0 +1,48 @@ +package alliance_gravity + +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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderAllianceGravity, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderAllianceGravity, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"srid":"11223344"}`, + `{"srid":"1122334455"}`, + `{"srid":"0"}`, + `{"srid":"11223344","other_params":"hoge"}`, +} + +var invalidParams = []string{ + `{}`, + `null`, + `12345`, + `{"id":123456}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 9a2aaa0bd2..e3f624fa83 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -39,6 +39,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/akcelo" "github.com/prebid/prebid-server/v3/adapters/algorix" "github.com/prebid/prebid-server/v3/adapters/alkimi" + alliance_gravity "github.com/prebid/prebid-server/v3/adapters/alliance_gravity" "github.com/prebid/prebid-server/v3/adapters/amx" "github.com/prebid/prebid-server/v3/adapters/apacdex" "github.com/prebid/prebid-server/v3/adapters/appnexus" @@ -305,6 +306,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAkcelo: akcelo.Builder, openrtb_ext.BidderAlgorix: algorix.Builder, openrtb_ext.BidderAlkimi: alkimi.Builder, + openrtb_ext.BidderAllianceGravity: alliance_gravity.Builder, openrtb_ext.BidderAMX: amx.Builder, openrtb_ext.BidderApacdex: apacdex.Builder, openrtb_ext.BidderAppnexus: appnexus.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 8cd543c1f1..50f626923e 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -55,6 +55,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAkcelo, BidderAlgorix, BidderAlkimi, + BidderAllianceGravity, BidderAMX, BidderApacdex, BidderAppnexus, @@ -428,6 +429,7 @@ const ( BidderAkcelo BidderName = "akcelo" BidderAlgorix BidderName = "algorix" BidderAlkimi BidderName = "alkimi" + BidderAllianceGravity BidderName = "alliance_gravity" BidderAMX BidderName = "amx" BidderApacdex BidderName = "apacdex" BidderAppnexus BidderName = "appnexus" diff --git a/openrtb_ext/imp_alliance_gravity.go b/openrtb_ext/imp_alliance_gravity.go new file mode 100644 index 0000000000..f63c46fe2b --- /dev/null +++ b/openrtb_ext/imp_alliance_gravity.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpAllianceGravity struct { + SrId string `json:"srid"` +} diff --git a/static/bidder-info/alliance_gravity.yaml b/static/bidder-info/alliance_gravity.yaml new file mode 100644 index 0000000000..2557de1e83 --- /dev/null +++ b/static/bidder-info/alliance_gravity.yaml @@ -0,0 +1,24 @@ +endpoint: "https://pbs.production.agrvt.com/openrtb2/auction" +maintainer: + email: produit@alliancegravity.com +gvlVendorID: 501 +modifyingVastXmlAllowed: true +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - audio + - native + site: + mediaTypes: + - banner + - video + - audio + - native +userSync: + iframe: + url: "https://pbs.production.agrvt.com/static/cookie_sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "$UID" diff --git a/static/bidder-params/alliance_gravity.json b/static/bidder-params/alliance_gravity.json new file mode 100644 index 0000000000..71135195ba --- /dev/null +++ b/static/bidder-params/alliance_gravity.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Alliance Gravity Adapter Params", + "description": "A schema which validates params accepted by the Alliance Gravity adapter", + "type": "object", + "properties": { + "srid": { + "type": "string", + "description": "Stored request ID", + "minLength": 1 + } + }, + + "required": ["srid"] +} From 92f8a91d2db81e5b2bfb25aa7c4551fab6b147c3 Mon Sep 17 00:00:00 2001 From: Postindustria <oss@postindustria.com> Date: Wed, 25 Feb 2026 04:31:00 +0200 Subject: [PATCH 169/272] ORTB Blocking Module: battr media type strictness (#4551) --- modules/prebid/ortb2blocking/config.go | 8 + .../ortb2blocking/hook_bidderrequest.go | 184 ++++- .../ortb2blocking/hook_bidderrequest_test.go | 738 ++++++++++++++++++ modules/prebid/ortb2blocking/module_test.go | 8 +- 4 files changed, 901 insertions(+), 37 deletions(-) create mode 100644 modules/prebid/ortb2blocking/hook_bidderrequest_test.go diff --git a/modules/prebid/ortb2blocking/config.go b/modules/prebid/ortb2blocking/config.go index 1990b0a56a..f41180155e 100644 --- a/modules/prebid/ortb2blocking/config.go +++ b/modules/prebid/ortb2blocking/config.go @@ -84,13 +84,21 @@ type BtypeActionOverride struct { type Battr struct { ActionOverrides BattrActionOverride `json:"action_overrides"` AllowedBannerAttrForDeals []int `json:"allowed_banner_attr_for_deals"` + AllowedVideoAttrForDeals []int `json:"allowed_video_attr_for_deals"` + AllowedAudioAttrForDeals []int `json:"allowed_audio_attr_for_deals"` BlockedBannerAttr []int `json:"blocked_banner_attr"` + BlockedVideoAttr []int `json:"blocked_video_attr"` + BlockedAudioAttr []int `json:"blocked_audio_attr"` EnforceBlocks bool `json:"enforce_blocks"` } type BattrActionOverride struct { AllowedBannerAttrForDeals []ActionOverride `json:"allowed_banner_attr_for_deals"` + AllowedVideoAttrForDeals []ActionOverride `json:"allowed_video_attr_for_deals"` + AllowedAudioAttrForDeals []ActionOverride `json:"allowed_audio_attr_for_deals"` BlockedBannerAttr []ActionOverride `json:"blocked_banner_attr"` + BlockedVideoAttr []ActionOverride `json:"blocked_video_attr"` + BlockedAudioAttr []ActionOverride `json:"blocked_audio_attr"` EnforceBlocks []ActionOverride `json:"enforce_blocks"` } diff --git a/modules/prebid/ortb2blocking/hook_bidderrequest.go b/modules/prebid/ortb2blocking/hook_bidderrequest.go index 4b3cb87c85..cd18de72dc 100644 --- a/modules/prebid/ortb2blocking/hook_bidderrequest.go +++ b/modules/prebid/ortb2blocking/hook_bidderrequest.go @@ -147,13 +147,22 @@ func updateBType( return imp.Banner != nil && len(imp.Banner.BType) > 0 } - attributes.bType, messages, err = findImpressionOverrides(payload, actionOverrides, btype, checkAttrExistence) + overrides, messages, err := findImpressionOverrides(payload, actionOverrides, btype, checkAttrExistence) result.Warnings = mergeStrings(result.Warnings, messages...) if err != nil { return fmt.Errorf("failed to get override for imp.*.banner.btype: %s", err) - } else if len(attributes.bType) > 0 { - mutation := bTypeMutation(attributes.bType) - changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "btype") + } + + // Filter to only apply to impressions with Banner objects + if len(overrides) > 0 { + filteredOverrides := filterByMediaType(payload, overrides, func(imp openrtb2.Imp) bool { + return imp.Banner != nil + }) + if len(filteredOverrides) > 0 { + mutation := createBTypeMutation(filteredOverrides) + changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "btype") + } + attributes.bType = overrides } return nil @@ -167,21 +176,91 @@ func updateBAttr( changeSet *hookstage.ChangeSet[hookstage.BidderRequestPayload], ) (err error) { var messages []string - battr := cfg.Attributes.Battr.BlockedBannerAttr - actionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedBannerAttr - checkAttrExistence := func(imp openrtb2.Imp) bool { + + bannerBattr := cfg.Attributes.Battr.BlockedBannerAttr + bannerActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedBannerAttr + bannerCheckAttrExistence := func(imp openrtb2.Imp) bool { return imp.Banner != nil && len(imp.Banner.BAttr) > 0 } - attributes.bAttr, messages, err = findImpressionOverrides(payload, actionOverrides, battr, checkAttrExistence) - result.Warnings = mergeStrings(result.Warnings, messages...) + bannerOverrides, bannerMessages, err := findImpressionOverrides(payload, bannerActionOverrides, bannerBattr, bannerCheckAttrExistence) + messages = append(messages, bannerMessages...) if err != nil { return fmt.Errorf("failed to get override for imp.*.banner.battr: %s", err) - } else if len(attributes.bAttr) > 0 { - mutation := bAttrMutation(attributes.bAttr) - changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "battr") } + // Apply banner battr only to impressions that have Banner objects + if len(bannerOverrides) > 0 { + filteredBannerOverrides := filterByMediaType(payload, bannerOverrides, func(imp openrtb2.Imp) bool { + return imp.Banner != nil + }) + if len(filteredBannerOverrides) > 0 { + mutation := createBAttrMutation(filteredBannerOverrides, "banner") + changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "battr") + } + } + + // Video battr + videoBattr := cfg.Attributes.Battr.BlockedVideoAttr + videoActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedVideoAttr + videoCheckAttrExistence := func(imp openrtb2.Imp) bool { + return imp.Video != nil && len(imp.Video.BAttr) > 0 + } + + videoOverrides, videoMessages, err := findImpressionOverrides(payload, videoActionOverrides, videoBattr, videoCheckAttrExistence) + messages = append(messages, videoMessages...) + if err != nil { + return fmt.Errorf("failed to get override for imp.*.video.battr: %s", err) + } + + // Apply video battr only to impressions that have Video objects + if len(videoOverrides) > 0 { + filteredVideoOverrides := filterByMediaType(payload, videoOverrides, func(imp openrtb2.Imp) bool { + return imp.Video != nil + }) + if len(filteredVideoOverrides) > 0 { + mutation := createBAttrMutation(filteredVideoOverrides, "video") + changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "video", "battr") + } + } + + // Audio battr + audioBattr := cfg.Attributes.Battr.BlockedAudioAttr + audioActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedAudioAttr + audioCheckAttrExistence := func(imp openrtb2.Imp) bool { + return imp.Audio != nil && len(imp.Audio.BAttr) > 0 + } + + audioOverrides, audioMessages, err := findImpressionOverrides(payload, audioActionOverrides, audioBattr, audioCheckAttrExistence) + messages = append(messages, audioMessages...) + if err != nil { + return fmt.Errorf("failed to get override for imp.*.audio.battr: %s", err) + } + + // Apply audio battr only to impressions that have Audio objects + if len(audioOverrides) > 0 { + filteredAudioOverrides := filterByMediaType(payload, audioOverrides, func(imp openrtb2.Imp) bool { + return imp.Audio != nil + }) + if len(filteredAudioOverrides) > 0 { + mutation := createBAttrMutation(filteredAudioOverrides, "audio") + changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "audio", "battr") + } + } + + // Store all attributes and merge messages + attributes.bAttr = make(map[string][]int) + for k, v := range bannerOverrides { + attributes.bAttr[k] = v + } + for k, v := range videoOverrides { + attributes.bAttr[k] = v + } + for k, v := range audioOverrides { + attributes.bAttr[k] = v + } + + result.Warnings = mergeStrings(result.Warnings, messages...) return nil } @@ -199,26 +278,6 @@ func updateCatTax( changeSet.BidderRequest().CatTax().Update(attributes.catTax) } -func bTypeMutation(bTypeByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] { - return mutationForImp(bTypeByImp, func(imp openrtb2.Imp, btype []int) openrtb2.Imp { - imp.Banner.BType = make([]openrtb2.BannerAdType, len(btype)) - for i := range btype { - imp.Banner.BType[i] = openrtb2.BannerAdType(btype[i]) - } - return imp - }) -} - -func bAttrMutation(bAttrByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] { - return mutationForImp(bAttrByImp, func(imp openrtb2.Imp, battr []int) openrtb2.Imp { - imp.Banner.BAttr = make([]adcom1.CreativeAttribute, len(battr)) - for i := range battr { - imp.Banner.BAttr[i] = adcom1.CreativeAttribute(battr[i]) - } - return imp - }) -} - type impUpdateFunc func(imp openrtb2.Imp, values []int) openrtb2.Imp func mutationForImp( @@ -422,3 +481,64 @@ func validateCondition(conditions Conditions) error { } return nil } + +// filterByMediaType filters overrides to only include impressions with a specific media type +func filterByMediaType( + payload hookstage.BidderRequestPayload, + overrides map[string][]int, + mediaTypeExists func(imp openrtb2.Imp) bool, +) map[string][]int { + filtered := make(map[string][]int) + + for _, imp := range payload.Request.Imp { + if values, exists := overrides[imp.ID]; exists && mediaTypeExists(imp) { + filtered[imp.ID] = values + } + } + + return filtered +} + +// createBAttrMutation creates a mutation function for a specific media type +func createBAttrMutation(bAttrByImp map[string][]int, mediaType string) hookstage.MutationFunc[hookstage.BidderRequestPayload] { + return func(payload hookstage.BidderRequestPayload) (hookstage.BidderRequestPayload, error) { + for i, imp := range payload.Request.Imp { + if values, ok := bAttrByImp[imp.ID]; ok && len(values) > 0 { + switch mediaType { + case "banner": + imp.Banner.BAttr = make([]adcom1.CreativeAttribute, len(values)) + for j, attr := range values { + imp.Banner.BAttr[j] = adcom1.CreativeAttribute(attr) + } + case "video": + imp.Video.BAttr = make([]adcom1.CreativeAttribute, len(values)) + for j, attr := range values { + imp.Video.BAttr[j] = adcom1.CreativeAttribute(attr) + } + case "audio": + imp.Audio.BAttr = make([]adcom1.CreativeAttribute, len(values)) + for j, attr := range values { + imp.Audio.BAttr[j] = adcom1.CreativeAttribute(attr) + } + } + payload.Request.Imp[i] = imp + } + } + return payload, nil + } +} + +func createBTypeMutation(bTypeByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] { + return func(payload hookstage.BidderRequestPayload) (hookstage.BidderRequestPayload, error) { + for i, imp := range payload.Request.Imp { + if values, ok := bTypeByImp[imp.ID]; ok && len(values) > 0 { + imp.Banner.BType = make([]openrtb2.BannerAdType, len(values)) + for j, btype := range values { + imp.Banner.BType[j] = openrtb2.BannerAdType(btype) + } + payload.Request.Imp[i] = imp + } + } + return payload, nil + } +} diff --git a/modules/prebid/ortb2blocking/hook_bidderrequest_test.go b/modules/prebid/ortb2blocking/hook_bidderrequest_test.go new file mode 100644 index 0000000000..5730bd5001 --- /dev/null +++ b/modules/prebid/ortb2blocking/hook_bidderrequest_test.go @@ -0,0 +1,738 @@ +package ortb2blocking + +import ( + "testing" + + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUpdateBAttr_DoesNotCreateMediaTypeObjects(t *testing.T) { + cfg := config{ + Attributes: Attributes{ + Battr: Battr{ + BlockedBannerAttr: []int{1, 2, 3}, + BlockedVideoAttr: []int{4, 5, 6}, + BlockedAudioAttr: []int{7, 8, 9}, + }, + }, + } + + var sizeW int64 = 640 + var sizeH int64 = 480 + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-video-only", + Video: &openrtb2.Video{W: &sizeW, H: &sizeH}, + // Banner = nil, Audio = nil + }, + { + ID: "imp-audio-only", + Audio: &openrtb2.Audio{}, + // Banner = nil, Video = nil + }, + }, + }, + }, + Bidder: "test-bidder", + } + + var blockingAttrs blockingAttributes + var result hookstage.HookResult[hookstage.BidderRequestPayload] + var changeSet hookstage.ChangeSet[hookstage.BidderRequestPayload] + + err := updateBAttr(cfg, payload, &blockingAttrs, &result, &changeSet) + require.NoError(t, err) + + // Check that mutations were created only for existing media types + mutations := changeSet.Mutations() + + // Check the number of mutations - there should be only one for video and one for audio + videoMutationsCount := 0 + audioMutationsCount := 0 + bannerMutationsCount := 0 + + for _, mutation := range mutations { + if len(mutation.Key()) >= 3 { + mediaType := mutation.Key()[2] // the third path element must be a media type + switch mediaType { + case "video": + videoMutationsCount++ + case "audio": + audioMutationsCount++ + case "banner": + bannerMutationsCount++ + } + } + } + + assert.Equal(t, 1, videoMutationsCount, "Should have exactly one video mutation") + assert.Equal(t, 1, audioMutationsCount, "Should have exactly one audio mutation") + assert.Equal(t, 0, bannerMutationsCount, "Should have no banner mutations") + + // Apply mutations manually using functions from the code + for _, mutation := range mutations { + updatedPayload, err := mutation.Apply(payload) + require.NoError(t, err) + payload = updatedPayload + } + + // Check that Banner/Audio objects were NOT created + for _, imp := range payload.Request.BidRequest.Imp { + switch imp.ID { + case "imp-video-only": + assert.NotNil(t, imp.Video, "Video should exist") + assert.Nil(t, imp.Banner, "Banner should NOT be created") + assert.Nil(t, imp.Audio, "Audio should NOT be created") + // Check that battr was added to video + if imp.Video != nil { + assert.Len(t, imp.Video.BAttr, 3, "Video should have battr applied") + } + case "imp-audio-only": + assert.NotNil(t, imp.Audio, "Audio should exist") + assert.Nil(t, imp.Banner, "Banner should NOT be created") + assert.Nil(t, imp.Video, "Video should NOT be created") + // Check that battr was added to audio + if imp.Audio != nil { + assert.Len(t, imp.Audio.BAttr, 3, "Audio should have battr applied") + } + } + } +} + +func TestUpdateBAttr_AppliesOnlyToExistingMediaTypes(t *testing.T) { + cfg := config{ + Attributes: Attributes{ + Battr: Battr{ + BlockedBannerAttr: []int{1, 2}, + BlockedVideoAttr: []int{3, 4}, + BlockedAudioAttr: []int{5, 6}, + }, + }, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-banner-only", + Banner: &openrtb2.Banner{W: ptrutil.ToPtr[int64](300), H: ptrutil.ToPtr[int64](250)}, + }, + { + ID: "imp-mixed", + Banner: &openrtb2.Banner{W: ptrutil.ToPtr[int64](728), H: ptrutil.ToPtr[int64](90)}, + Video: &openrtb2.Video{W: ptrutil.ToPtr[int64](640), H: ptrutil.ToPtr[int64](480)}, + }, + }, + }, + }, + Bidder: "test-bidder", + } + + var blockingAttrs blockingAttributes + var result hookstage.HookResult[hookstage.BidderRequestPayload] + var changeSet hookstage.ChangeSet[hookstage.BidderRequestPayload] + + err := updateBAttr(cfg, payload, &blockingAttrs, &result, &changeSet) + require.NoError(t, err) + + // We apply mutations + mutations := changeSet.Mutations() + for _, mutation := range mutations { + updatedPayload, err := mutation.Apply(payload) + require.NoError(t, err) + payload = updatedPayload + } + + for _, imp := range payload.Request.BidRequest.Imp { + switch imp.ID { + case "imp-banner-only": + assert.NotNil(t, imp.Banner, "Banner should exist") + assert.Nil(t, imp.Video, "Video should NOT be created") + assert.Nil(t, imp.Audio, "Audio should NOT be created") + if imp.Banner != nil { + assert.Len(t, imp.Banner.BAttr, 2, "Banner should have battr applied") + } + case "imp-mixed": + assert.NotNil(t, imp.Banner, "Banner should exist") + assert.NotNil(t, imp.Video, "Video should exist") + assert.Nil(t, imp.Audio, "Audio should NOT be created") + if imp.Banner != nil { + assert.Len(t, imp.Banner.BAttr, 2, "Banner should have battr applied") + } + if imp.Video != nil { + assert.Len(t, imp.Video.BAttr, 2, "Video should have battr applied") + } + } + } +} + +func TestFilterByMediaType(t *testing.T) { + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "has-banner", + Banner: &openrtb2.Banner{}, + }, + { + ID: "no-banner", + // Banner = nil + }, + }, + }, + }, + } + + overrides := map[string][]int{ + "has-banner": {1, 2, 3}, + "no-banner": {4, 5, 6}, + } + + filtered := filterByMediaType(payload, overrides, func(imp openrtb2.Imp) bool { + return imp.Banner != nil + }) + + // Only the impression with the Banner should remain. + assert.Len(t, filtered, 1) + assert.Contains(t, filtered, "has-banner") + assert.NotContains(t, filtered, "no-banner") + assert.Equal(t, []int{1, 2, 3}, filtered["has-banner"]) +} + +func TestCreateBAttrMutation(t *testing.T) { + bAttrByImp := map[string][]int{ + "imp1": {1, 2}, + "imp2": {3, 4}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{}, + }, + { + ID: "imp2", + Banner: &openrtb2.Banner{}, + }, + }, + }, + }, + } + + mutation := createBAttrMutation(bAttrByImp, "banner") + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + // Check that battr was applied + for _, imp := range updatedPayload.Request.BidRequest.Imp { + switch imp.ID { + case "imp1": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BAttr, 2) + assert.Equal(t, adcom1.CreativeAttribute(1), imp.Banner.BAttr[0]) + assert.Equal(t, adcom1.CreativeAttribute(2), imp.Banner.BAttr[1]) + case "imp2": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BAttr, 2) + assert.Equal(t, adcom1.CreativeAttribute(3), imp.Banner.BAttr[0]) + assert.Equal(t, adcom1.CreativeAttribute(4), imp.Banner.BAttr[1]) + } + } +} + +func TestCreateBTypeMutation(t *testing.T) { + bTypeByImp := map[string][]int{ + "imp1": {1, 2}, + "imp2": {3, 4}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{}, + }, + { + ID: "imp2", + Banner: &openrtb2.Banner{}, + }, + }, + }, + }, + } + + mutation := createBTypeMutation(bTypeByImp) + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + // Check that btype was applied + for _, imp := range updatedPayload.Request.BidRequest.Imp { + switch imp.ID { + case "imp1": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BType, 2) + assert.Equal(t, openrtb2.BannerAdType(1), imp.Banner.BType[0]) + assert.Equal(t, openrtb2.BannerAdType(2), imp.Banner.BType[1]) + case "imp2": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BType, 2) + assert.Equal(t, openrtb2.BannerAdType(3), imp.Banner.BType[0]) + assert.Equal(t, openrtb2.BannerAdType(4), imp.Banner.BType[1]) + } + } +} + +func TestUpdateBType_DoesNotCreateBannerObjects(t *testing.T) { + cfg := config{ + Attributes: Attributes{ + Btype: Btype{ + BlockedBannerType: []int{1, 2, 3}, + }, + }, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp-video-only", + Video: &openrtb2.Video{W: ptrutil.ToPtr[int64](640), H: ptrutil.ToPtr[int64](480)}, + }, + { + ID: "imp-with-banner", + Banner: &openrtb2.Banner{}, + }, + }, + }, + }, + Bidder: "test-bidder", + } + + var blockingAttrs blockingAttributes + var result hookstage.HookResult[hookstage.BidderRequestPayload] + var changeSet hookstage.ChangeSet[hookstage.BidderRequestPayload] + + err := updateBType(cfg, payload, &blockingAttrs, &result, &changeSet) + require.NoError(t, err) + + // Apply mutations + mutations := changeSet.Mutations() + for _, mutation := range mutations { + updatedPayload, err := mutation.Apply(payload) + require.NoError(t, err) + payload = updatedPayload + } + + // Check that Banner was NOT created for video-only impression + for _, imp := range payload.Request.BidRequest.Imp { + switch imp.ID { + case "imp-video-only": + assert.NotNil(t, imp.Video, "Video should exist") + assert.Nil(t, imp.Banner, "Banner should NOT be created") + case "imp-with-banner": + assert.NotNil(t, imp.Banner, "Banner should exist") + assert.Len(t, imp.Banner.BType, 3, "Banner should have btype applied") + } + } +} + +func TestCreateBAttrMutation_EmptyValues(t *testing.T) { + bAttrByImp := map[string][]int{ + "imp1": {}, + "imp2": {1, 2}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{}, + }, + { + ID: "imp2", + Banner: &openrtb2.Banner{}, + }, + }, + }, + }, + } + + mutation := createBAttrMutation(bAttrByImp, "banner") + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + // Check that empty values are handled correctly + for _, imp := range updatedPayload.Request.BidRequest.Imp { + switch imp.ID { + case "imp1": + require.NotNil(t, imp.Banner) + // Empty array should result in empty BAttr + assert.Len(t, imp.Banner.BAttr, 0) + case "imp2": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BAttr, 2) + } + } +} + +func TestCreateBTypeMutation_EmptyValues(t *testing.T) { + bTypeByImp := map[string][]int{ + "imp1": {}, + "imp2": {1, 2}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{}, + }, + { + ID: "imp2", + Banner: &openrtb2.Banner{}, + }, + }, + }, + }, + } + + mutation := createBTypeMutation(bTypeByImp) + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + for _, imp := range updatedPayload.Request.BidRequest.Imp { + switch imp.ID { + case "imp1": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BType, 0) + case "imp2": + require.NotNil(t, imp.Banner) + assert.Len(t, imp.Banner.BType, 2) + } + } +} + +func TestMediaTypesFrom(t *testing.T) { + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{}, + Video: &openrtb2.Video{}, + }, + { + ID: "imp2", + Audio: &openrtb2.Audio{}, + }, + }, + } + + mediaTypes := mediaTypesFrom(request) + + assert.Len(t, mediaTypes, 3) + assert.Contains(t, mediaTypes, "banner") + assert.Contains(t, mediaTypes, "video") + assert.Contains(t, mediaTypes, "audio") + assert.NotContains(t, mediaTypes, "native") +} + +func TestMediaTypesFromImp(t *testing.T) { + tests := []struct { + name string + imp openrtb2.Imp + expected []string + }{ + { + name: "banner only", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + }, + expected: []string{"banner"}, + }, + { + name: "video only", + imp: openrtb2.Imp{ + Video: &openrtb2.Video{}, + }, + expected: []string{"video"}, + }, + { + name: "audio only", + imp: openrtb2.Imp{ + Audio: &openrtb2.Audio{}, + }, + expected: []string{"audio"}, + }, + { + name: "native only", + imp: openrtb2.Imp{ + Native: &openrtb2.Native{}, + }, + expected: []string{"native"}, + }, + { + name: "multiple types", + imp: openrtb2.Imp{ + Banner: &openrtb2.Banner{}, + Video: &openrtb2.Video{}, + Audio: &openrtb2.Audio{}, + }, + expected: []string{"banner", "video", "audio"}, + }, + { + name: "no media types", + imp: openrtb2.Imp{}, + expected: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := mediaTypesFromImp(tt.imp) + assert.Len(t, result, len(tt.expected)) + for _, mt := range tt.expected { + assert.Contains(t, result, mt) + } + }) + } +} + +func TestMediaTypes_String(t *testing.T) { + tests := []struct { + name string + mt mediaTypes + expected string + }{ + { + name: "multiple types sorted", + mt: mediaTypes{ + "video": struct{}{}, + "banner": struct{}{}, + "audio": struct{}{}, + }, + expected: "audio, banner, video", + }, + { + name: "empty", + mt: mediaTypes{}, + expected: "", + }, + { + name: "all types", + mt: mediaTypes{ + "audio": struct{}{}, + "banner": struct{}{}, + "native": struct{}{}, + "video": struct{}{}, + }, + expected: "audio, banner, native, video", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.mt.String() + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestMediaTypes_Intersects(t *testing.T) { + mt := mediaTypes{ + "banner": struct{}{}, + "video": struct{}{}, + } + + tests := []struct { + name string + input []string + expected bool + }{ + { + name: "exact match", + input: []string{"banner"}, + expected: true, + }, + { + name: "case insensitive match", + input: []string{"BANNER"}, + expected: true, + }, + { + name: "multiple with match", + input: []string{"audio", "video"}, + expected: true, + }, + { + name: "no match", + input: []string{"audio", "native"}, + expected: false, + }, + { + name: "empty input", + input: []string{}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := mt.intersects(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestValidateCondition(t *testing.T) { + tests := []struct { + name string + condition Conditions + wantErr bool + }{ + { + name: "valid - bidders only", + condition: Conditions{ + Bidders: []string{"bidder1"}, + }, + wantErr: false, + }, + { + name: "valid - media types only", + condition: Conditions{ + MediaTypes: []string{"banner"}, + }, + wantErr: false, + }, + { + name: "valid - both present", + condition: Conditions{ + Bidders: []string{"bidder1"}, + MediaTypes: []string{"banner"}, + }, + wantErr: false, + }, + { + name: "invalid - both absent", + condition: Conditions{}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateCondition(tt.condition) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestFilterByMediaType_NoMatches(t *testing.T) { + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Video: &openrtb2.Video{}, + }, + }, + }, + }, + } + + overrides := map[string][]int{ + "imp1": {1, 2, 3}, + } + + // Filter for Banner, but impression has only Video + filtered := filterByMediaType(payload, overrides, func(imp openrtb2.Imp) bool { + return imp.Banner != nil + }) + + assert.Len(t, filtered, 0, "Should not include impressions without matching media type") +} + +func TestCreateBAttrMutation_VideoMediaType(t *testing.T) { + bAttrByImp := map[string][]int{ + "imp1": {1, 2}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Video: &openrtb2.Video{}, + }, + }, + }, + }, + } + + mutation := createBAttrMutation(bAttrByImp, "video") + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + imp := updatedPayload.Request.BidRequest.Imp[0] + require.NotNil(t, imp.Video) + assert.Len(t, imp.Video.BAttr, 2) + assert.Equal(t, adcom1.CreativeAttribute(1), imp.Video.BAttr[0]) + assert.Equal(t, adcom1.CreativeAttribute(2), imp.Video.BAttr[1]) +} + +func TestCreateBAttrMutation_AudioMediaType(t *testing.T) { + bAttrByImp := map[string][]int{ + "imp1": {7, 8, 9}, + } + + payload := hookstage.BidderRequestPayload{ + Request: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Audio: &openrtb2.Audio{}, + }, + }, + }, + }, + } + + mutation := createBAttrMutation(bAttrByImp, "audio") + updatedPayload, err := mutation(payload) + require.NoError(t, err) + + imp := updatedPayload.Request.BidRequest.Imp[0] + require.NotNil(t, imp.Audio) + assert.Len(t, imp.Audio.BAttr, 3) + assert.Equal(t, adcom1.CreativeAttribute(7), imp.Audio.BAttr[0]) + assert.Equal(t, adcom1.CreativeAttribute(8), imp.Audio.BAttr[1]) + assert.Equal(t, adcom1.CreativeAttribute(9), imp.Audio.BAttr[2]) +} diff --git a/modules/prebid/ortb2blocking/module_test.go b/modules/prebid/ortb2blocking/module_test.go index 17008b2dad..4159d73f34 100644 --- a/modules/prebid/ortb2blocking/module_test.go +++ b/modules/prebid/ortb2blocking/module_test.go @@ -307,8 +307,9 @@ func TestHandleBidderRequestHook(t *testing.T) { Video: &openrtb2.Video{}, }, { - ID: "ImpID2", - Audio: &openrtb2.Audio{}, + ID: "ImpID2", + Audio: &openrtb2.Audio{}, + Banner: &openrtb2.Banner{}, }, }, }, @@ -391,7 +392,6 @@ func TestHandleBidderRequestHook(t *testing.T) { ModuleContext: map[string]interface{}{ bidder: blockingAttributes{ bAdv: []string{bAdvA, bAdvB, bAdvC}, - bType: map[string][]int{}, bAttr: map[string][]int{}, }, }, @@ -440,7 +440,6 @@ func TestHandleBidderRequestHook(t *testing.T) { }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ ModuleContext: map[string]interface{}{bidder: blockingAttributes{ - bType: map[string][]int{}, bAttr: map[string][]int{}, }}, }, @@ -461,7 +460,6 @@ func TestHandleBidderRequestHook(t *testing.T) { }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ ModuleContext: map[string]interface{}{bidder: blockingAttributes{ - bType: map[string][]int{}, bAttr: map[string][]int{}, }}, }, From 4e111e9de10a8abf2da5a0aa551939505b78ccfe Mon Sep 17 00:00:00 2001 From: linux019 <anode.dev@gmail.com> Date: Wed, 25 Feb 2026 06:00:09 +0200 Subject: [PATCH 170/272] Log nested structures from the configuration (#4519) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- config/structlog.go | 8 ++++++-- config/structlog_test.go | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/config/structlog.go b/config/structlog.go index 6faec25cc5..4b088f2315 100644 --- a/config/structlog.go +++ b/config/structlog.go @@ -37,6 +37,10 @@ func logGeneralWithLogger(v reflect.Value, prefix string, logger logMsg) { logger("%s: %f", prefix, v.Float()) case reflect.Bool: logger("%s: %t", prefix, v.Bool()) + case reflect.Ptr: + if v.Elem().IsValid() { + logGeneralWithLogger(v.Elem(), prefix, logger) + } default: // logString, by using v.String(), will not fail, and indicate what additional cases we need to handle logger("%s: %s", prefix, v.String()) @@ -45,7 +49,7 @@ func logGeneralWithLogger(v reflect.Value, prefix string, logger logMsg) { func logStructWithLogger(v reflect.Value, prefix string, logger logMsg) { if v.Kind() != reflect.Struct { - logInternal.Fatalf("LogStruct called on type %s, whuch is not a struct!", v.Type().String()) + logInternal.Fatalf("LogStruct called on type %s, which is not a struct!", v.Type().String()) } t := v.Type() for i := 0; i < t.NumField(); i++ { @@ -60,7 +64,7 @@ func logStructWithLogger(v reflect.Value, prefix string, logger logMsg) { func logMapWithLogger(v reflect.Value, prefix string, logger logMsg) { if v.Kind() != reflect.Map { - logInternal.Fatalf("LogMap called on type %s, whuch is not a map!", v.Type().String()) + logInternal.Fatalf("LogMap called on type %s, which is not a map!", v.Type().String()) } for _, k := range v.MapKeys() { if k.Kind() == reflect.String && !allowedName(k.String()) { diff --git a/config/structlog_test.go b/config/structlog_test.go index d7ed720c73..d0e3c91da9 100644 --- a/config/structlog_test.go +++ b/config/structlog_test.go @@ -8,11 +8,13 @@ import ( ) type testStruct struct { - Myint int `mapstructure:"this_int"` - Mystring string `mapstructure:"mystring"` - Flag bool - Sub innerStruct `mapstructure:"sub"` - Caps map[string]string + Myint int `mapstructure:"this_int"` + Mystring string `mapstructure:"mystring"` + Flag bool + Sub innerStruct `mapstructure:"sub"` + Caps map[string]string + NestedStruct *nestedStruct + NillableStruct *nestedStruct } type innerStruct struct { @@ -20,12 +22,17 @@ type innerStruct struct { password string `mapstructure:"password"` } +type nestedStruct struct { + var1 string +} + var expected string = `this_int: 5 mystring: foobar ((Flag)): false sub.int1: 3 sub.password: <REDACTED> ((Caps))[Alabama]: Montgomery +((NestedStruct)).((var1)): abc ` func TestBasic(t *testing.T) { @@ -46,6 +53,8 @@ func TestBasic(t *testing.T) { Caps: map[string]string{ "Alabama": "Montgomery", }, + NestedStruct: &nestedStruct{var1: "abc"}, + NillableStruct: nil, } logStructWithLogger(reflect.ValueOf(testCfg), "", mylogger) From d8d4a1b87441d78325389f1cec5657633f771a0e Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:58:27 -0500 Subject: [PATCH 171/272] HTTP Fetcher: Enable RFC 3986 by Default (#4681) --- config/config.go | 4 ++-- config/config_test.go | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 2c3acefab2..e7c4951f7b 100644 --- a/config/config.go +++ b/config/config.go @@ -1044,7 +1044,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("stored_requests.directorypath", "./stored_requests/data/by_id") v.SetDefault("stored_requests.http.endpoint", "") v.SetDefault("stored_requests.http.amp_endpoint", "") - v.SetDefault("stored_requests.http.use_rfc3986_compliant_request_builder", false) + v.SetDefault("stored_requests.http.use_rfc3986_compliant_request_builder", true) v.SetDefault("stored_requests.in_memory_cache.type", "none") v.SetDefault("stored_requests.in_memory_cache.ttl_seconds", 0) v.SetDefault("stored_requests.in_memory_cache.request_cache_size_bytes", 0) @@ -1135,7 +1135,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("accounts.filesystem.enabled", false) v.SetDefault("accounts.filesystem.directorypath", "./stored_requests/data/by_id") v.SetDefault("accounts.http.endpoint", "") - v.SetDefault("accounts.http.use_rfc3986_compliant_request_builder", false) + v.SetDefault("accounts.http.use_rfc3986_compliant_request_builder", true) v.SetDefault("accounts.in_memory_cache.type", "none") v.SetDefault("accounts.in_memory_cache.ttl_seconds", 0) v.SetDefault("accounts.in_memory_cache.size_bytes", 0) diff --git a/config/config_test.go b/config/config_test.go index f310c99e8d..ed66234c8c 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -167,12 +167,12 @@ func TestDefaults(t *testing.T) { cmpStrings(t, "stored_requests.filesystem.directorypath", "./stored_requests/data/by_id", cfg.StoredRequests.Files.Path) cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) - cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", true, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) cmpBools(t, "video.enable_deprecated_endpoint", false, cfg.Video.EnableDeprecatedEndpoint) cmpBools(t, "accounts.filesystem.enabled", false, cfg.Accounts.Files.Enabled) cmpStrings(t, "accounts.filesystem.directorypath", "./stored_requests/data/by_id", cfg.Accounts.Files.Path) cmpStrings(t, "accounts.http.endpoint", "", cfg.Accounts.HTTP.Endpoint) - cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", false, cfg.Accounts.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", true, cfg.Accounts.HTTP.UseRfcCompliantBuilder) cmpStrings(t, "accounts.in_memory_cache.type", "none", cfg.Accounts.InMemoryCache.Type) cmpInts(t, "accounts.in_memory_cache.ttl_seconds", 0, cfg.Accounts.InMemoryCache.TTL) cmpInts(t, "accounts.in_memory_cache.size_bytes", 0, cfg.Accounts.InMemoryCache.Size) @@ -370,7 +370,7 @@ accounts: directorypath: "./example_directory" http: endpoint: "https://prebid.org" - use_rfc3986_compliant_request_builder: true + use_rfc3986_compliant_request_builder: false in_memory_cache: type: "lru" ttl_seconds: 300 @@ -659,11 +659,11 @@ func TestFullConfig(t *testing.T) { cmpInts(t, "stored_request_timeout_ms", 75, cfg.StoredRequestsTimeout) cmpStrings(t, "stored_requests.http.endpoint", "", cfg.StoredRequests.HTTP.Endpoint) cmpStrings(t, "stored_requests.http.amp_endpoint", "", cfg.StoredRequests.HTTP.AmpEndpoint) - cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", false, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "stored_requests.http.use_rfc3986_compliant_request_builder", true, cfg.StoredRequests.HTTP.UseRfcCompliantBuilder) cmpBools(t, "accounts.filesystem.enabled", true, cfg.Accounts.Files.Enabled) cmpStrings(t, "accounts.filesystem.directorypath", "./example_directory", cfg.Accounts.Files.Path) cmpStrings(t, "accounts.http.endpoint", "https://prebid.org", cfg.Accounts.HTTP.Endpoint) - cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", true, cfg.Accounts.HTTP.UseRfcCompliantBuilder) + cmpBools(t, "accounts.http.use_rfc3986_compliant_request_builder", false, cfg.Accounts.HTTP.UseRfcCompliantBuilder) cmpStrings(t, "accounts.in_memory_cache.type", "lru", cfg.Accounts.InMemoryCache.Type) cmpInts(t, "accounts.in_memory_cache.ttl_seconds", 300, cfg.Accounts.InMemoryCache.TTL) cmpInts(t, "accounts.in_memory_cache.size_bytes", 1000, cfg.Accounts.InMemoryCache.Size) From 4898ef00419a5c9147eb3d39f3def5f74d74a5b6 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:07:06 -0500 Subject: [PATCH 172/272] Intertech: Remove Adapter (#4680) --- adapters/intertech/intertech.go | 226 ------------------ adapters/intertech/intertech_test.go | 21 -- .../exemplary/simple-banner-muli-format.json | 115 --------- .../exemplary/simple-banner.json | 119 --------- .../exemplary/simple-native.json | 103 -------- .../supplemental/bad_media_type.json | 100 -------- .../supplemental/bad_response.json | 79 ------ .../supplemental/invalid-banner-size.json | 35 --- .../supplemental/invalid-bidder.json | 28 --- .../supplemental/invalid-ext.json | 30 --- .../supplemental/no-cur-req.json | 71 ------ .../intertechtest/supplemental/no-device.json | 105 -------- .../supplemental/no-site-req.json | 67 ------ .../supplemental/status-204.json | 73 ------ .../supplemental/status-not-200.json | 78 ------ adapters/intertech/params_test.go | 48 ---- exchange/adapter_builders.go | 2 - exchange/adapter_util.go | 1 + openrtb_ext/bidders.go | 2 - openrtb_ext/imp_intertech.go | 6 - static/bidder-info/intertech.yaml | 15 -- static/bidder-params/intertech.json | 21 -- 22 files changed, 1 insertion(+), 1344 deletions(-) delete mode 100644 adapters/intertech/intertech.go delete mode 100644 adapters/intertech/intertech_test.go delete mode 100644 adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json delete mode 100644 adapters/intertech/intertechtest/exemplary/simple-banner.json delete mode 100644 adapters/intertech/intertechtest/exemplary/simple-native.json delete mode 100644 adapters/intertech/intertechtest/supplemental/bad_media_type.json delete mode 100644 adapters/intertech/intertechtest/supplemental/bad_response.json delete mode 100644 adapters/intertech/intertechtest/supplemental/invalid-banner-size.json delete mode 100644 adapters/intertech/intertechtest/supplemental/invalid-bidder.json delete mode 100644 adapters/intertech/intertechtest/supplemental/invalid-ext.json delete mode 100644 adapters/intertech/intertechtest/supplemental/no-cur-req.json delete mode 100644 adapters/intertech/intertechtest/supplemental/no-device.json delete mode 100644 adapters/intertech/intertechtest/supplemental/no-site-req.json delete mode 100644 adapters/intertech/intertechtest/supplemental/status-204.json delete mode 100644 adapters/intertech/intertechtest/supplemental/status-not-200.json delete mode 100644 adapters/intertech/params_test.go delete mode 100644 openrtb_ext/imp_intertech.go delete mode 100644 static/bidder-info/intertech.yaml delete mode 100644 static/bidder-params/intertech.json diff --git a/adapters/intertech/intertech.go b/adapters/intertech/intertech.go deleted file mode 100644 index ae491995a7..0000000000 --- a/adapters/intertech/intertech.go +++ /dev/null @@ -1,226 +0,0 @@ -package intertech - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "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" -) - -const ( - pageIDMacro = "{{page_id}}" - impIDMacro = "{{imp_id}}" -) - -type adapter struct { - endpoint string -} - -func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - bidder := &adapter{ - endpoint: config.Endpoint, - } - return bidder, nil -} - -func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - var errs []error - var requests []*adapters.RequestData - - referer := getReferer(request) - cur := getCur(request) - - for _, imp := range request.Imp { - extImp, err := parseAndValidateImpExt(imp) - if err != nil { - errs = append(errs, err) - continue - } - - modifiedImp, err := modifyImp(imp) - if err != nil { - errs = append(errs, err) - continue - } - - modifiedUrl := a.modifyUrl(extImp, referer, cur) - - modRequest := *request - modRequest.Imp = []openrtb2.Imp{modifiedImp} - - reqData, err := buildRequestData(modRequest, modifiedUrl) - if err != nil { - errs = append(errs, err) - continue - } - - requests = append(requests, reqData) - } - - return requests, errs -} - -func parseAndValidateImpExt(imp openrtb2.Imp) (openrtb_ext.ExtImpIntertech, error) { - var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { - return openrtb_ext.ExtImpIntertech{}, &errortypes.BadInput{ - Message: fmt.Sprintf("imp #%s: unable to parse bidder ext: %s", imp.ID, err), - } - } - - var extImp openrtb_ext.ExtImpIntertech - if err := jsonutil.Unmarshal(bidderExt.Bidder, &extImp); err != nil { - return openrtb_ext.ExtImpIntertech{}, &errortypes.BadInput{ - Message: fmt.Sprintf("imp #%s: unable to parse intertech ext: %s", imp.ID, err), - } - } - - return extImp, nil -} - -func modifyImp(imp openrtb2.Imp) (openrtb2.Imp, error) { - if imp.Banner != nil { - banner, err := updateBanner(imp.Banner) - if err != nil { - return openrtb2.Imp{}, &errortypes.BadInput{ - Message: fmt.Sprintf("imp #%s: %s", imp.ID, err.Error()), - } - } - imp.Banner = banner - } - return imp, nil -} - -func updateBanner(banner *openrtb2.Banner) (*openrtb2.Banner, error) { - bannerCopy := *banner - if bannerCopy.W == nil || bannerCopy.H == nil || *bannerCopy.W == 0 || *bannerCopy.H == 0 { - if len(bannerCopy.Format) > 0 { - w := bannerCopy.Format[0].W - h := bannerCopy.Format[0].H - bannerCopy.W = &w - bannerCopy.H = &h - } else { - return nil, fmt.Errorf("Invalid sizes provided for Banner") - } - } - return &bannerCopy, nil -} - -func (a *adapter) modifyUrl(extImp openrtb_ext.ExtImpIntertech, referer, cur string) string { - pageStr := strconv.Itoa(extImp.PageID) - impStr := strconv.Itoa(extImp.ImpID) - - resolvedUrl := strings.ReplaceAll(a.endpoint, pageIDMacro, url.QueryEscape(pageStr)) - resolvedUrl = strings.ReplaceAll(resolvedUrl, impIDMacro, url.QueryEscape(impStr)) - - if referer != "" { - resolvedUrl += "&target-ref=" + url.QueryEscape(referer) - } - - if cur != "" { - resolvedUrl += "&ssp-cur=" + cur - } - - return resolvedUrl -} - -func buildRequestData(bidRequest openrtb2.BidRequest, uri string) (*adapters.RequestData, error) { - body, err := jsonutil.Marshal(bidRequest) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Add("Content-Type", "application/json;charset=utf-8") - headers.Add("Accept", "application/json") - - if bidRequest.Device != nil { - if bidRequest.Device.UA != "" { - headers.Add("User-Agent", bidRequest.Device.UA) - } - if bidRequest.Device.IP != "" { - headers.Add("X-Forwarded-For", bidRequest.Device.IP) - headers.Add("X-Real-Ip", bidRequest.Device.IP) - } - if bidRequest.Device.Language != "" { - headers.Add("Accept-Language", bidRequest.Device.Language) - } - } - return &adapters.RequestData{ - Method: http.MethodPost, - Uri: uri, - Body: body, - Headers: headers, - ImpIDs: openrtb_ext.GetImpIDs(bidRequest.Imp), - }, nil -} - -func getReferer(request *openrtb2.BidRequest) string { - if request.Site != nil { - return request.Site.Page - } - return "" -} - -func getCur(request *openrtb2.BidRequest) string { - if len(request.Cur) > 0 { - return request.Cur[0] - } - return "" -} - -func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if adapters.IsResponseStatusCodeNoContent(responseData) { - return nil, nil - } - - if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { - return nil, []error{err} - } - - var response openrtb2.BidResponse - if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { - return nil, []error{err} - } - - bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) - if len(response.Cur) != 0 { - bidResponse.Currency = response.Cur - } - - for _, seatBid := range response.SeatBid { - for i := range seatBid.Bid { - bid := seatBid.Bid[i] - bidType, err := getBidType(bid) - if err != nil { - return nil, []error{err} - } - - b := &adapters.TypedBid{ - Bid: &seatBid.Bid[i], - BidType: bidType, - } - bidResponse.Bids = append(bidResponse.Bids, b) - } - } - return bidResponse, nil -} - -func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { - switch bid.MType { - case openrtb2.MarkupBanner: - return openrtb_ext.BidTypeBanner, nil - case openrtb2.MarkupNative: - return openrtb_ext.BidTypeNative, nil - } - - return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) -} diff --git a/adapters/intertech/intertech_test.go b/adapters/intertech/intertech_test.go deleted file mode 100644 index 952b2a4431..0000000000 --- a/adapters/intertech/intertech_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package intertech - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderIntertech, config.Adapter{ - Endpoint: "https://test.intertech.com/ssp?pid={{page_id}}&imp={{imp_id}}"}, config.Server{ - ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, "intertechtest", bidder) -} diff --git a/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json b/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json deleted file mode 100644 index 39f1262628..0000000000 --- a/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "mockBidRequest": { - "id": "request-id-1", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "site": { - "page": "http://bannercheck.com" - }, - "imp": [ - { - "id": "imp-id-1", - "tagid": "tag-id-1", - "banner": { - "format": [ - { "w": 728, "h": 90 }, - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1111, - "imp_id": 2222 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1111&imp=2222&target-ref=http%3A%2F%2Fbannercheck.com&ssp-cur=USD", - "body": { - "id": "request-id-1", - "imp": [ - { - "id": "imp-id-1", - "tagid": "tag-id-1", - "banner": { - "w": 728, - "h": 90, - "format": [ - { "w": 728, "h": 90 }, - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1111, - "imp_id": 2222 - } - } - } - ], - "site": { - "page": "http://bannercheck.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "cur": ["USD"] - }, - "impIDs": ["imp-id-1"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "request-id-1", - "cur": "USD", - "seatbid": [ - { - "seat": "intertech", - "bid": [ - { - "id": "bid-id-1", - "impid": "imp-id-1", - "price": 0.7, - "adm": "<html><body><h1>Test Banner 728x90</h1></body></html>", - "cid": "campaign-id-1", - "crid": "creative-id-1", - "w": 728, - "h": 90, - "mtype": 1 - } - ] - } - ] - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "bid-id-1", - "impid": "imp-id-1", - "price": 0.7, - "adm": "<html><body><h1>Test Banner 728x90</h1></body></html>", - "cid": "campaign-id-1", - "crid": "creative-id-1", - "w": 728, - "h": 90, - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/intertech/intertechtest/exemplary/simple-banner.json b/adapters/intertech/intertechtest/exemplary/simple-banner.json deleted file mode 100644 index dc0473465a..0000000000 --- a/adapters/intertech/intertechtest/exemplary/simple-banner.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)", - "language": "en-US" - }, - "site": { - "page": "mypage" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=mypage&ssp-cur=USD", - "headers": { - "Content-Type": ["application/json;charset=utf-8"], - "Accept": ["application/json"], - "Accept-Language": ["en-US"], - "User-Agent": ["Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)"], - "X-Forwarded-For": ["123.123.123.123"], - "X-Real-Ip": ["123.123.123.123"] - }, - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "site": { - "page": "mypage" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)", - "language": "en-US" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "cur": "USD", - "seatbid": [ - { - "seat": "intertech", - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.5, - "adm": "<html><body><h1>Test Ad</h1></body></html>", - "cid": "test_cid", - "crid": "test_crid", - "w": 300, - "h": 250, - "mtype": 1 - } - ] - } - ] - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.5, - "adm": "<html><body><h1>Test Ad</h1></body></html>", - "cid": "test_cid", - "crid": "test_crid", - "w": 300, - "h": 250, - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/intertech/intertechtest/exemplary/simple-native.json b/adapters/intertech/intertechtest/exemplary/simple-native.json deleted file mode 100644 index a9336b8ffb..0000000000 --- a/adapters/intertech/intertechtest/exemplary/simple-native.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-native-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)" - }, - "site": { - "page": "nativepage" - }, - "imp": [ - { - "id": "test-native-imp-id", - "tagid": "test-native-tag", - "native": { - "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}}],\"eventtrackers\":[{\"event\":1,\"method\":1}],\"ver\":\"1.2\"}" - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 4004 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=3003&imp=4004&target-ref=nativepage&ssp-cur=USD", - "body": { - "id": "test-native-request-id", - "imp": [ - { - "id": "test-native-imp-id", - "tagid": "test-native-tag", - "native": { - "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}}],\"eventtrackers\":[{\"event\":1,\"method\":1}],\"ver\":\"1.2\"}" - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 4004 - } - } - } - ], - "site": { - "page": "nativepage" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-native-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-native-request-id", - "cur": "USD", - "seatbid": [ - { - "seat": "intertech", - "bid": [ - { - "id": "test_native_bid_id", - "impid": "test-native-imp-id", - "price": 1.0, - "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Native Title\"}}],\"link\":{\"url\":\"http://example.com\"},\"imptrackers\":[\"http://example.com/imp\"]}}", - "cid": "test_native_cid", - "crid": "test_native_crid", - "mtype": 4 - } - ] - } - ] - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_native_bid_id", - "impid": "test-native-imp-id", - "price": 1.0, - "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Native Title\"}}],\"link\":{\"url\":\"http://example.com\"},\"imptrackers\":[\"http://example.com/imp\"]}}", - "cid": "test_native_cid", - "crid": "test_native_crid", - "mtype": 4 - }, - "type": "native" - } - ] - } - ] -} \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/bad_media_type.json b/adapters/intertech/intertechtest/supplemental/bad_media_type.json deleted file mode 100644 index 4e1074f136..0000000000 --- a/adapters/intertech/intertechtest/supplemental/bad_media_type.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "site": { - "page": "http://example.com" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 5005 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=3003&imp=5005&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 5005 - } - } - } - ], - "site": { - "page": "http://example.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "cur": "USD", - "seatbid": [ - { - "seat": "intertech", - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.5, - "adm": "<html><body><h1>Test Ad</h1></body></html>", - "cid": "test_cid", - "crid": "test_crid", - "w": 300, - "h": 250, - "mtype": 2 - } - ] - } - ] - } - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "could not define media type for impression: test-imp-id", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/bad_response.json b/adapters/intertech/intertechtest/supplemental/bad_response.json deleted file mode 100644 index 6ca58d71dd..0000000000 --- a/adapters/intertech/intertechtest/supplemental/bad_response.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "site": { - "page": "http://example.com" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "site": { - "page": "http://example.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": "" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] - } - \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json b/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json deleted file mode 100644 index 49d6a4996c..0000000000 --- a/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-invalid-sizes-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "site": { - "page": "http://no-size-banner.com" - }, - "imp": [ - { - "id": "test-imp-no-size", - "tagid": "no-size-tag", - "banner": { - "format": [] - }, - "ext": { - "bidder": { - "page_id": 1111, - "imp_id": 9999 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [], - "expectedMakeRequestsErrors": [ - { - "value": "imp #test-imp-no-size: Invalid sizes provided for Banner", - "comparison": "literal" - } - ] -} diff --git a/adapters/intertech/intertechtest/supplemental/invalid-bidder.json b/adapters/intertech/intertechtest/supplemental/invalid-bidder.json deleted file mode 100644 index 0f530a0e68..0000000000 --- a/adapters/intertech/intertechtest/supplemental/invalid-bidder.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-req-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": "badBidder" - } - } - ] - }, - - "expectedMakeRequestsErrors": [ - { - "value": "imp #test-imp-id: unable to parse intertech ext: expect { or n, but found \"", - "comparison": "literal" - } - ] -} diff --git a/adapters/intertech/intertechtest/supplemental/invalid-ext.json b/adapters/intertech/intertechtest/supplemental/invalid-ext.json deleted file mode 100644 index 4c8eb9c9c7..0000000000 --- a/adapters/intertech/intertechtest/supplemental/invalid-ext.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-req-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": 123 - } - ] - }, - - "httpCalls": [], - - "expectedBidResponses": [], - - "expectedMakeRequestsErrors": [ - { - "value": "imp #test-imp-id: unable to parse bidder ext: expect { or n, but found 1", - "comparison": "literal" - } - ] -} diff --git a/adapters/intertech/intertechtest/supplemental/no-cur-req.json b/adapters/intertech/intertechtest/supplemental/no-cur-req.json deleted file mode 100644 index a6101b6023..0000000000 --- a/adapters/intertech/intertechtest/supplemental/no-cur-req.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-no-cur-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "site": { - "page": "http://example-nocur.com" - }, - "imp": [ - { - "id": "test-imp-no-cur", - "tagid": "no-cur-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1111, - "imp_id": 2222 - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1111&imp=2222&target-ref=http%3A%2F%2Fexample-nocur.com", - "body": { - "id": "test-no-cur-request-id", - "imp": [ - { - "id": "test-imp-no-cur", - "tagid": "no-cur-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1111, - "imp_id": 2222 - } - } - } - ], - "site": { - "page": "http://example-nocur.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - } - }, - "impIDs": ["test-imp-no-cur"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - } - ], - "expectedBidResponses": [] -} diff --git a/adapters/intertech/intertechtest/supplemental/no-device.json b/adapters/intertech/intertechtest/supplemental/no-device.json deleted file mode 100644 index 8f811e0709..0000000000 --- a/adapters/intertech/intertechtest/supplemental/no-device.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-no-device", - "site": { - "page": "mypage" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=mypage&ssp-cur=USD", - "headers": { - "Content-Type": ["application/json;charset=utf-8"], - "Accept": ["application/json"] - }, - "body": { - "id": "test-request-no-device", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "site": { - "page": "mypage" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-no-device", - "cur": "USD", - "seatbid": [ - { - "seat": "intertech", - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.5, - "adm": "<html><body><h1>Test Ad</h1></body></html>", - "cid": "test_cid", - "crid": "test_crid", - "w": 300, - "h": 250, - "mtype": 1 - } - ] - } - ] - } - } - } - ], - "expectedBidResponses": [ - { - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.5, - "adm": "<html><body><h1>Test Ad</h1></body></html>", - "cid": "test_cid", - "crid": "test_crid", - "w": 300, - "h": 250, - "mtype": 1 - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/intertech/intertechtest/supplemental/no-site-req.json b/adapters/intertech/intertechtest/supplemental/no-site-req.json deleted file mode 100644 index 9d4901994b..0000000000 --- a/adapters/intertech/intertechtest/supplemental/no-site-req.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-no-site-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "imp": [ - { - "id": "test-imp-no-site", - "tagid": "no-site-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 5005 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=3003&imp=5005&ssp-cur=USD", - "body": { - "id": "test-no-site-request-id", - "imp": [ - { - "id": "test-imp-no-site", - "tagid": "no-site-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 3003, - "imp_id": 5005 - } - } - } - ], - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (X11; Linux x86_64)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-no-site"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - } - ], - "expectedBidResponses": [] -} diff --git a/adapters/intertech/intertechtest/supplemental/status-204.json b/adapters/intertech/intertechtest/supplemental/status-204.json deleted file mode 100644 index 8225c9ea57..0000000000 --- a/adapters/intertech/intertechtest/supplemental/status-204.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "site": { - "page": "http://example.com" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "site": { - "page": "http://example.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 204, - "body": {} - } - } - ], - "expectedBidResponses": [] -} diff --git a/adapters/intertech/intertechtest/supplemental/status-not-200.json b/adapters/intertech/intertechtest/supplemental/status-not-200.json deleted file mode 100644 index 58317e359f..0000000000 --- a/adapters/intertech/intertechtest/supplemental/status-not-200.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "site": { - "page": "http://mypage.com" - }, - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "cur": ["USD"] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fmypage.com&ssp-cur=USD", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "tagid": "test-tag", - "banner": { - "w": 300, - "h": 250, - "format": [ - { "w": 300, "h": 250 } - ] - }, - "ext": { - "bidder": { - "page_id": 1001, - "imp_id": 2002 - } - } - } - ], - "site": { - "page": "http://mypage.com" - }, - "device": { - "ip": "123.123.123.123", - "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" - }, - "cur": ["USD"] - }, - "impIDs": ["test-imp-id"] - }, - "mockResponse": { - "status": 404, - "body": {} - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} diff --git a/adapters/intertech/params_test.go b/adapters/intertech/params_test.go deleted file mode 100644 index eb7bb0aba4..0000000000 --- a/adapters/intertech/params_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package intertech - -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 schema. %v", err) - } - - for _, p := range validParams { - if err := validator.Validate(openrtb_ext.BidderIntertech, json.RawMessage(p)); err != nil { - t.Errorf("Schema rejected valid params: %s", p) - } - } -} - -func TestInvalidParams(t *testing.T) { - validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") - if err != nil { - t.Fatalf("Failed to fetch the json schema. %v", err) - } - - for _, p := range invalidParams { - if err := validator.Validate(openrtb_ext.BidderIntertech, json.RawMessage(p)); err == nil { - t.Errorf("Schema allowed invalid params: %s", p) - } - } -} - -var validParams = []string{ - `{"page_id": 123, "imp_id": 456}`, - `{"page_id": 1, "imp_id": 1}`, - `{"page_id": 999, "imp_id": 999}`, -} - -var invalidParams = []string{ - `{"page_id": "abc", "imp_id": 1}`, - `{"page_id": "1", "imp_id": abc}`, - `{"page_id": "123123"}`, - `{"imp_id": "123"}`, - `{}`, -} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e3f624fa83..96fdfd61fa 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -125,7 +125,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/insticator" "github.com/prebid/prebid-server/v3/adapters/intenze" "github.com/prebid/prebid-server/v3/adapters/interactiveoffers" - "github.com/prebid/prebid-server/v3/adapters/intertech" "github.com/prebid/prebid-server/v3/adapters/invibes" "github.com/prebid/prebid-server/v3/adapters/iqx" "github.com/prebid/prebid-server/v3/adapters/iqzone" @@ -393,7 +392,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderInsticator: insticator.Builder, openrtb_ext.BidderIntenze: intenze.Builder, openrtb_ext.BidderInteractiveoffers: interactiveoffers.Builder, - openrtb_ext.BidderIntertech: intertech.Builder, openrtb_ext.BidderInvibes: invibes.Builder, openrtb_ext.BidderIQX: iqx.Builder, openrtb_ext.BidderIQZone: iqzone.Builder, diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 377130118e..879ef75a8b 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -127,6 +127,7 @@ func GetDisabledBidderWarningMessages(infos config.BidderInfos) map[string]strin "bizzclick": `Bidder "bizzclick" is no longer available in Prebid Server. Please update your configuration. "bizzclick" has been renamed to "blasto".`, "liftoff": `Bidder "liftoff" is no longer available in Prebid Server. If you're looking to use the Vungle Exchange adapter, please rename it to "vungle" in your configuration.`, "gothamads": `Bidder "gothamads" is no longer available in Prebid Server. Please rename it to "intenze" in your configuration.`, + "intertech": `Bidder "intertech" is no longer available in Prebid Server. Please update your configuration.`, "adocean": `Bidder "adocean" is no longer available in Prebid Server. Please update your configuration.`, "dxkulture": `Bidder "dxkulture" is no longer available in Prebid Server. Please update your configuration.`, "mobupps": `Bidder "mobupps" is no longer available in Prebid Server. Please update your configuration.`, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 50f626923e..de628a5dc4 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -142,7 +142,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderInsticator, BidderIntenze, BidderInteractiveoffers, - BidderIntertech, BidderInvibes, BidderIQX, BidderIQZone, @@ -516,7 +515,6 @@ const ( BidderInsticator BidderName = "insticator" BidderIntenze BidderName = "intenze" BidderInteractiveoffers BidderName = "interactiveoffers" - BidderIntertech BidderName = "intertech" BidderInvibes BidderName = "invibes" BidderIQX BidderName = "iqx" BidderIQZone BidderName = "iqzone" diff --git a/openrtb_ext/imp_intertech.go b/openrtb_ext/imp_intertech.go deleted file mode 100644 index 7c0bc955c5..0000000000 --- a/openrtb_ext/imp_intertech.go +++ /dev/null @@ -1,6 +0,0 @@ -package openrtb_ext - -type ExtImpIntertech struct { - PageID int `json:"page_id"` - ImpID int `json:"imp_id"` -} diff --git a/static/bidder-info/intertech.yaml b/static/bidder-info/intertech.yaml deleted file mode 100644 index bf4b52bc38..0000000000 --- a/static/bidder-info/intertech.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# This adapter is ported from PBS-Java to PBS-Go by Prebid. Please open a GitHub issue instead of -# directly contacting the maintainer for technical issues. -endpoint: https://prebid.intertechsrvcs.com/prebid/{{.PageID}}?imp-id={{.ImpID}}&ssp-id=10500 -endpointCompression: GZIP -maintainer: - email: prebid@intertechsrvcs.com -capabilities: - site: - mediaTypes: - - banner - - native -userSync: - redirect: - url: https://prebid.intertechsrvcs.com/mapuid/intertech/?ssp-id=10500&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&location= - userMacro: "{UID}" \ No newline at end of file diff --git a/static/bidder-params/intertech.json b/static/bidder-params/intertech.json deleted file mode 100644 index 8b1e3daa6c..0000000000 --- a/static/bidder-params/intertech.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Intertech Adapter Params", - "description": "A schema which validates params accepted by the Intertech adapter", - "type": "object", - "properties": { - "page_id": { - "type": "integer", - "minLength": 1, - "description": "Special Page Id provided by Intertech Manager" - }, - "imp_id": { - "type": "integer", - "minLength": 1, - "description": "Special identifier provided by Intertech Manager" - } - }, - "required": - ["page_id", - "imp_id"] -} \ No newline at end of file From 064b4afc50ade7a8cf2b14ee3f9e415ce1b73ff0 Mon Sep 17 00:00:00 2001 From: Philip Watson <philip.watson@adscale.co.nz> Date: Wed, 4 Mar 2026 02:31:01 +1300 Subject: [PATCH 173/272] Stroeercore: Use bid.ext as-is from the response (#4633) --- adapters/stroeerCore/stroeercore.go | 31 +-- .../stroeercoretest/exemplary/bid-ext.json | 207 ++++++++++++++++++ ...json => deprecated-json-path-for-dsa.json} | 6 +- 3 files changed, 229 insertions(+), 15 deletions(-) create mode 100644 adapters/stroeerCore/stroeercoretest/exemplary/bid-ext.json rename adapters/stroeerCore/stroeercoretest/exemplary/{dsa.json => deprecated-json-path-for-dsa.json} (97%) diff --git a/adapters/stroeerCore/stroeercore.go b/adapters/stroeerCore/stroeercore.go index 57dc2b0cd7..087a9de7e9 100644 --- a/adapters/stroeerCore/stroeercore.go +++ b/adapters/stroeerCore/stroeercore.go @@ -32,12 +32,10 @@ type bidResponse struct { Ad string `json:"ad"` CrID string `json:"crid"` Mtype string `json:"mtype"` - DSA json.RawMessage `json:"dsa"` ADomain []string `json:"adomain,omitempty"` -} - -type bidExt struct { - DSA json.RawMessage `json:"dsa,omitempty"` + Ext json.RawMessage `json:"ext,omitempty"` + // Deprecated: The dsa will move to the bid response's ext. + DSA json.RawMessage `json:"dsa"` } func (b *bidResponse) resolveMediaType() (mt openrtb2.MarkupType, bt openrtb_ext.BidType, err error) { @@ -88,15 +86,7 @@ func (a *adapter) MakeBids(bidRequest *openrtb2.BidRequest, requestData *adapter CrID: bid.CrID, MType: markupType, ADomain: bid.ADomain, - } - - if bid.DSA != nil { - dsaJson, err := json.Marshal(bidExt{bid.DSA}) - if err != nil { - errors = append(errors, err) - } else { - openRtbBid.Ext = dsaJson - } + Ext: getBidExt(bid), } bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ @@ -108,6 +98,19 @@ func (a *adapter) MakeBids(bidRequest *openrtb2.BidRequest, requestData *adapter return bidderResponse, errors } +func getBidExt(bid bidResponse) json.RawMessage { + if bid.DSA == nil { + return bid.Ext + } + extMap := map[string]json.RawMessage{} + if bid.Ext != nil { + _ = jsonutil.Unmarshal(bid.Ext, &extMap) + } + extMap["dsa"] = bid.DSA + ext, _ := json.Marshal(extMap) + return ext +} + func (a *adapter) MakeRequests(bidRequest *openrtb2.BidRequest, extraRequestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errors []error diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/bid-ext.json b/adapters/stroeerCore/stroeercoretest/exemplary/bid-ext.json new file mode 100644 index 0000000000..43e997e25b --- /dev/null +++ b/adapters/stroeerCore/stroeercoretest/exemplary/bid-ext.json @@ -0,0 +1,207 @@ +{ + "mockBidRequest": { + "id": "auction-id", + "cur": [ + "EUR" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "sid": "123456" + } + } + } + ], + "device": { + "ip": "123.123.123.123" + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path" + }, + "user": { + "buyeruid": "test-buyer-user-id" + }, + "regs": { + "ext": { + "dsa": { + "dsarequired": 3, + "pubrender": 0, + "datatopub": 2, + "transparency": [ + { + "domain": "example-platform.com", + "dsaparams": [ + 1 + ] + }, + { + "domain": "example-ssp.com", + "dsaparams": [ + 1, + 2 + ] + } + ] + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "uri": "http://localhost/s2sdsh", + "body": { + "id": "auction-id", + "cur": [ + "EUR" + ], + "imp": [ + { + "id": "1", + "tagid": "123456", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "sid": "123456" + } + } + } + ], + "device": { + "ip": "123.123.123.123" + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path" + }, + "user": { + "buyeruid": "test-buyer-user-id" + }, + "regs": { + "ext": { + "dsa": { + "dsarequired": 3, + "pubrender": 0, + "datatopub": 2, + "transparency": [ + { + "domain": "example-platform.com", + "dsaparams": [ + 1 + ] + }, + { + "domain": "example-ssp.com", + "dsaparams": [ + 1, + 2 + ] + } + ] + } + } + } + }, + "impIDs":["1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "bids": [ + { + "id": "1829273982920-01", + "bidId": "1", + "cpm": 2, + "width": 300, + "height": 600, + "ad": "advert", + "crid": "wasd", + "mtype": "banner", + "ext": { + "other": "thing", + "dsa": { + "behalf": "Advertiser A", + "paid": "Advertiser B", + "transparency": [ + { + "domain": "example-domain.com", + "dsaparams": [ + 1, + 2 + ] + } + ], + "adrender": 1 + } + } + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "1829273982920-01", + "impid": "1", + "price": 2, + "adm": "advert", + "w": 300, + "h": 600, + "crid": "wasd", + "mtype": 1, + "ext": { + "other": "thing", + "dsa": { + "behalf": "Advertiser A", + "paid": "Advertiser B", + "transparency": [ + { + "domain": "example-domain.com", + "dsaparams": [ + 1, + 2 + ] + } + ], + "adrender": 1 + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/dsa.json b/adapters/stroeerCore/stroeercoretest/exemplary/deprecated-json-path-for-dsa.json similarity index 97% rename from adapters/stroeerCore/stroeercoretest/exemplary/dsa.json rename to adapters/stroeerCore/stroeercoretest/exemplary/deprecated-json-path-for-dsa.json index 97355da905..b2c21511d5 100644 --- a/adapters/stroeerCore/stroeercoretest/exemplary/dsa.json +++ b/adapters/stroeerCore/stroeercoretest/exemplary/deprecated-json-path-for-dsa.json @@ -157,6 +157,9 @@ } ], "adrender": 1 + }, + "ext": { + "something": "else" } } ] @@ -192,7 +195,8 @@ } ], "adrender": 1 - } + }, + "something": "else" } }, "type": "banner" From 2d3f2852f41ae09487b620174647b6a28539e6be Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Tue, 3 Mar 2026 19:44:40 +0530 Subject: [PATCH 174/272] Insticator: Support OpenRTB 2.6 and add app endpoint (#4668) --- adapters/insticator/insticator.go | 112 +++- adapters/insticator/insticator_test.go | 4 +- .../insticatortest/exemplary/app-banner.json | 219 ++++--- .../insticatortest/exemplary/app-video.json | 22 +- .../exemplary/multi-format.json | 228 ++++--- .../insticatortest/exemplary/multi-imps.json | 577 ++++++++++-------- .../insticatortest/exemplary/site-banner.json | 16 +- .../insticatortest/exemplary/site-video.json | 88 ++- .../insticatortest/supplemental/204.json | 126 ++-- .../supplemental/app-pubid-absent.json | 194 +++--- .../supplemental/bad-imp-ext.json | 55 +- .../currency-conversion-fail.json | 78 +-- .../supplemental/currency-conversion.json | 277 ++++----- .../supplemental/device-validation.json | 7 +- .../multi-imp-mixed-validation.json | 268 ++++---- .../request-ext-unmarshal-fail.json | 40 +- .../supplemental/response-unmarshal-fail.json | 190 +++--- .../supplemental/site-pubid-absent.json | 194 +++--- .../supplemental/status-not-ok.json | 151 ++--- .../supplemental/video-validation-fail.json | 54 +- static/bidder-info/insticator.yaml | 4 + static/bidder-params/insticator.json | 2 +- 22 files changed, 1617 insertions(+), 1289 deletions(-) diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index fc8487971b..e6e3866376 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -3,6 +3,7 @@ package insticator import ( "fmt" "net/http" + "net/url" "strings" "github.com/prebid/openrtb/v20/openrtb2" @@ -24,7 +25,12 @@ type impInsticatorExt struct { } type adapter struct { - endpoint string + endpoint string + extraInfo ExtraInfo +} + +type ExtraInfo struct { + AppEndpoint string `json:"app_endpoint,omitempty"` } type reqExt struct { @@ -54,12 +60,53 @@ type bidInsticatorExt struct { // Builder builds a new instance of the Insticator adapter with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + extraInfo, err := parseExtraInfo(config.ExtraAdapterInfo) + if err != nil { + return nil, err + } + bidder := &adapter{ - endpoint: config.Endpoint, + endpoint: config.Endpoint, + extraInfo: extraInfo, } return bidder, nil } +func parseExtraInfo(v string) (ExtraInfo, error) { + if len(v) == 0 { + return ExtraInfo{}, nil + } + + var extraInfo ExtraInfo + if err := jsonutil.Unmarshal([]byte(v), &extraInfo); err != nil { + return extraInfo, fmt.Errorf("invalid extra info: %v", err) + } + + return extraInfo, nil +} + +// buildEndpointURL builds the endpoint URL with publisherId query parameter +func (a *adapter) buildEndpointURL(publisherId string, request *openrtb2.BidRequest) string { + // Use app endpoint from extra_info if this is an app request + baseEndpoint := a.endpoint + if request.App != nil && a.extraInfo.AppEndpoint != "" { + baseEndpoint = a.extraInfo.AppEndpoint + } + + // Append publisherId as query parameter + if publisherId != "" { + parsedURL, err := url.Parse(baseEndpoint) + if err == nil { + query := parsedURL.Query() + query.Set("publisherId", publisherId) + parsedURL.RawQuery = query.Encode() + return parsedURL.String() + } + } + + return baseEndpoint +} + // getMediaTypeForBid figures out which media type this bid is for func getMediaTypeForBid(bid *openrtb2.Bid) openrtb_ext.BidType { switch bid.MType { @@ -76,6 +123,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte var errs []error var adapterRequests []*adapters.RequestData var groupedImps = make(map[string][]openrtb2.Imp) + var publisherId string reqExt, err := makeReqExt(request) if err != nil { @@ -89,14 +137,15 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte isPublisherIdPopulated := false // Flag to track if populatePublisherId has been called for i := 0; i < len(request.Imp); i++ { - impCopy, impKey, publisherId, err := makeImps(request.Imp[i]) + impCopy, impKey, impPublisherId, err := makeImps(request.Imp[i]) if err != nil { errs = append(errs, err) continue } - // Populate publisher.id from imp extension + // Populate publisher.id from imp extension (only once) if !isPublisherIdPopulated { + publisherId = impPublisherId populatePublisherId(publisherId, &requestCopy) isPublisherIdPopulated = true } @@ -118,7 +167,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte } for _, impList := range groupedImps { - if adapterReq, err := a.makeRequest(&requestCopy, impList); err == nil { + if adapterReq, err := a.makeRequest(&requestCopy, impList, publisherId); err == nil { adapterRequests = append(adapterRequests, adapterReq) } else { errs = append(errs, err) @@ -127,7 +176,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte return adapterRequests, errs } -func (a *adapter) makeRequest(request *openrtb2.BidRequest, impList []openrtb2.Imp) (*adapters.RequestData, error) { +func (a *adapter) makeRequest(request *openrtb2.BidRequest, impList []openrtb2.Imp, publisherId string) (*adapters.RequestData, error) { request.Imp = impList reqJSON, err := jsonutil.Marshal(request) @@ -135,6 +184,9 @@ func (a *adapter) makeRequest(request *openrtb2.BidRequest, impList []openrtb2.I return nil, err } + // Build endpoint URL with publisherId query parameter + endpointURL := a.buildEndpointURL(publisherId, request) + headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") @@ -156,7 +208,7 @@ func (a *adapter) makeRequest(request *openrtb2.BidRequest, impList []openrtb2.I return &adapters.RequestData{ Method: "POST", - Uri: a.endpoint, + Uri: endpointURL, Body: reqJSON, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(request.Imp), @@ -186,8 +238,11 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R bid := &seatBid.Bid[i] bidType := getMediaTypeForBid(bid) b := &adapters.TypedBid{ - Bid: &seatBid.Bid[i], - BidType: bidType, + Bid: &seatBid.Bid[i], + BidType: bidType, + BidMeta: getBidMeta(bid, bidType), + BidVideo: getBidVideo(bid, bidType), + Seat: openrtb_ext.BidderName(seatBid.Seat), } bidResponse.Bids = append(bidResponse.Bids, b) } @@ -195,6 +250,41 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R return bidResponse, nil } +// getBidMeta extracts metadata from the bid for brand safety and reporting +func getBidMeta(bid *openrtb2.Bid, bidType openrtb_ext.BidType) *openrtb_ext.ExtBidPrebidMeta { + meta := &openrtb_ext.ExtBidPrebidMeta{ + MediaType: string(bidType), + } + + if len(bid.ADomain) > 0 { + meta.AdvertiserDomains = bid.ADomain + } + + if len(bid.Cat) > 0 { + meta.PrimaryCategoryID = bid.Cat[0] + meta.SecondaryCategoryIDs = bid.Cat[1:] + } + + return meta +} + +// getBidVideo extracts video-specific metadata from the bid +func getBidVideo(bid *openrtb2.Bid, bidType openrtb_ext.BidType) *openrtb_ext.ExtBidPrebidVideo { + if bidType != openrtb_ext.BidTypeVideo { + return nil + } + + var primaryCategory string + if len(bid.Cat) > 0 { + primaryCategory = bid.Cat[0] + } + + return &openrtb_ext.ExtBidPrebidVideo{ + Duration: int(bid.Dur), + PrimaryCategory: primaryCategory, + } +} + func makeImps(imp openrtb2.Imp) (openrtb2.Imp, string, string, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { @@ -229,13 +319,13 @@ func makeImps(imp openrtb2.Imp) (openrtb2.Imp, string, string, error) { // Validate Video if it exists if imp.Video != nil { if err := validateVideoParams(imp.Video); err != nil { - return openrtb2.Imp{}, insticatorExt.AdUnitId, insticatorExt.PublisherId, &errortypes.BadInput{ + return openrtb2.Imp{}, "", insticatorExt.PublisherId, &errortypes.BadInput{ Message: err.Error(), } } } - // Return the imp, AdUnitId, and no error + // Return the imp, adUnitId as groupKey, publisherId, and no error return imp, insticatorExt.AdUnitId, insticatorExt.PublisherId, nil } diff --git a/adapters/insticator/insticator_test.go b/adapters/insticator/insticator_test.go index b557aedce4..1000697800 100644 --- a/adapters/insticator/insticator_test.go +++ b/adapters/insticator/insticator_test.go @@ -10,7 +10,9 @@ import ( func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderInsticator, config.Adapter{ - Endpoint: "https://insticator.example.com/v1/pbs"}, + Endpoint: "https://insticator.example.com/v1/pbs", + ExtraAdapterInfo: `{"app_endpoint": "https://insticator-app.example.com/v1/pbs"}`, + }, config.Server{ExternalUrl: "https://insticator.example.com/v1/pbs", GvlID: 1, DataCenter: "2"}) if buildErr != nil { diff --git a/adapters/insticator/insticatortest/exemplary/app-banner.json b/adapters/insticator/insticatortest/exemplary/app-banner.json index 4c71760a73..4b32c066ad 100644 --- a/adapters/insticator/insticatortest/exemplary/app-banner.json +++ b/adapters/insticator/insticatortest/exemplary/app-banner.json @@ -1,85 +1,99 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "app": { - "publisher": { - "id": "test-publisher-id" - } - }, - "device": { - "ua": "", - "ip": "1.1.1.2", - "ipv6": "" + } + ], + "app": { + "publisher": { + "id": "test-publisher-id" } }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "device":{ - "ip": "1.1.1.2" - }, - "ext": { - "insticator": { - "caller": [ + "device": { + "ua": "", + "ip": "1.1.1.2", + "ipv6": "" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator-app.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "device": { + "ip": "1.1.1.2" + }, + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "app": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id"] + ], + "app": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [{ + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1"], "crid": "crid_10", "h": 90, "w": 728, @@ -89,39 +103,46 @@ "mediaType": "banner" } } - }] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1"], + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + }, + "BidMeta": { + "advertiserDomains": ["insticator.com"], + "mediaType": "banner", + "primaryCatId": "IAB1" + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/exemplary/app-video.json b/adapters/insticator/insticatortest/exemplary/app-video.json index 2f0143fe96..1002fe9a0c 100644 --- a/adapters/insticator/insticatortest/exemplary/app-video.json +++ b/adapters/insticator/insticatortest/exemplary/app-video.json @@ -59,7 +59,7 @@ "1.22.22.1" ] }, - "uri": "https://insticator.example.com/v1/pbs", + "uri": "https://insticator-app.example.com/v1/pbs?publisherId=test-publisher-id", "body": { "device": { "ip": "1.22.22.1", @@ -125,8 +125,11 @@ { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-vast-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1-1"], + "dur": 30, "mtype": 2, "crid": "crid_10", "h": 90, @@ -155,6 +158,9 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1-1"], + "dur": 30, "crid": "crid_10", "w": 728, "mtype": 2, @@ -165,7 +171,17 @@ } } }, - "type": "video" + "BidMeta": { + "advertiserDomains": ["insticator.com"], + "mediaType": "video", + "primaryCatId": "IAB1-1" + }, + "BidVideo": { + "duration": 30, + "primary_category": "IAB1-1" + }, + "type": "video", + "seat": "insticator" } ] } diff --git a/adapters/insticator/insticatortest/exemplary/multi-format.json b/adapters/insticator/insticatortest/exemplary/multi-format.json index 1fedfe8dc9..3013569713 100644 --- a/adapters/insticator/insticatortest/exemplary/multi-format.json +++ b/adapters/insticator/insticatortest/exemplary/multi-format.json @@ -1,121 +1,147 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "video": { - "w": 728, - "h": 90, - "protocols": [2], - "playbackmethod": [2], - "mimes": ["foo", "bar"] - }, - "ext": { - "bidder": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "video": { + "w": 728, + "h": 90, + "protocols": [ + 2 + ], + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "video": { - "w": 728, - "h": 90, - "protocols": [2], - "playbackmethod": [2], - "mimes": ["foo", "bar"] - }, - "ext": { - "insticator": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" - } + }, + "video": { + "w": 728, + "h": 90, + "protocols": [ + 2 + ], + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id"] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [{ + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, "w": 728 - }] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90 - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/exemplary/multi-imps.json b/adapters/insticator/insticatortest/exemplary/multi-imps.json index eb744ced11..5d5531b73e 100644 --- a/adapters/insticator/insticatortest/exemplary/multi-imps.json +++ b/adapters/insticator/insticatortest/exemplary/multi-imps.json @@ -1,137 +1,175 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id1", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } - } + ] }, - { - "id": "test-imp-id2", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" - } + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } - }, - { - "id": "test-imp-id3", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } - } + ] }, - { - "id": "test-imp-id4", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "siab", - "publisherId": "test-publisher-id" + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id": "test-imp-id3", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" + }, + { + "id": "test-imp-id4", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "adUnitId": "siab", + "publisherId": "test-publisher-id" + } } } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } } }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id1", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } - } + ] }, - { - "id":"test-imp-id2", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" - } + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } - }, - { - "id":"test-imp-id3", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "inview", - "publisherId": "test-publisher-id" + } + }, + { + "id": "test-imp-id3", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id1","test-imp-id2", "test-imp-id3"] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [ - { + "impIDs": [ + "test-imp-id1", + "test-imp-id2", + "test-imp-id3" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id1", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, @@ -141,91 +179,98 @@ "mediaType": "banner" } } - }, - { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id2", - "price": 0.600000, - "adm": "some-test-ad", - "crid": "crid_10", - "h": 90, - "w": 728, - "ext": { - "insticator": { - "mediaType": "banner" - } + }, + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.6, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id3", - "price": 0.500000, - "adm": "some-test-ad", - "crid": "crid_10", - "h": 90, - "w": 728, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + }, + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id3", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" } } - ] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } - }, - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + } + }, + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id4", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id4", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "siab", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "siab", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id4"] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [ - { + "impIDs": [ + "test-imp-id4" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id4", - "price": 0.500000, + "impid": "test-imp-id4", + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, @@ -235,95 +280,97 @@ "mediaType": "banner" } } - } - ] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id1", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" + } }, - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id2", - "price": 0.6, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "ext": { - "insticator": { - "mediaType": "banner" - } + "type": "banner", + "seat": "insticator" + }, + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.6, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" + } }, - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id3", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "ext": { - "insticator": { - "mediaType": "banner" - } + "type": "banner", + "seat": "insticator" + }, + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id3", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - }, - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id4", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + }, + "type": "banner", + "seat": "insticator" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id4", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/exemplary/site-banner.json b/adapters/insticator/insticatortest/exemplary/site-banner.json index 4586fdc176..da7a463ce0 100644 --- a/adapters/insticator/insticatortest/exemplary/site-banner.json +++ b/adapters/insticator/insticatortest/exemplary/site-banner.json @@ -47,7 +47,7 @@ "2001:0db8:85a3:0000:0000:8a2e:0370:7334" ] }, - "uri": "https://insticator.example.com/v1/pbs", + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", "body": { "device": { "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", @@ -104,8 +104,10 @@ { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1"], "crid": "crid_10", "h": 90, "w": 728, @@ -134,6 +136,8 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1"], "crid": "crid_10", "w": 728, "h": 90, @@ -144,7 +148,13 @@ } } }, - "type": "banner" + "BidMeta": { + "advertiserDomains": ["insticator.com"], + "mediaType": "banner", + "primaryCatId": "IAB1" + }, + "type": "banner", + "seat": "insticator" } ] } diff --git a/adapters/insticator/insticatortest/exemplary/site-video.json b/adapters/insticator/insticatortest/exemplary/site-video.json index bd7c40af20..dc220773f3 100644 --- a/adapters/insticator/insticatortest/exemplary/site-video.json +++ b/adapters/insticator/insticatortest/exemplary/site-video.json @@ -5,13 +5,20 @@ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, - "protocols": [2], + "protocols": [ + 2 + ], "placement": 1, "startdelay": -2, - "playbackmethod": [2], - "mimes": ["foo", "bar"] + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] }, "ext": { "bidder": { @@ -27,11 +34,10 @@ } } }, - "httpCalls": [ { "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", "body": { "ext": { "insticator": { @@ -46,15 +52,22 @@ "id": "test-request-id", "imp": [ { - "id":"test-imp-id", + "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, - "protocols": [2], + "protocols": [ + 2 + ], "placement": 1, "startdelay": -2, - "playbackmethod": [2], - "mimes": ["foo", "bar"] + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] }, "ext": { "insticator": { @@ -70,7 +83,9 @@ } } }, - "impIDs":["test-imp-id"] + "impIDs": [ + "test-imp-id" + ] }, "mockResponse": { "status": 200, @@ -79,21 +94,26 @@ "seatbid": [ { "seat": "insticator", - "bid": [{ - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.500000, - "adm": "some-test-vast-ad", - "mtype": 2, - "crid": "crid_10", - "h": 90, - "w": 728, - "ext": { - "insticator": { - "mediaType": "video" + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-vast-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1-1"], + "dur": 30, + "mtype": 2, + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "video" + } } } - }] + ] } ], "cur": "USD" @@ -101,7 +121,6 @@ } } ], - "expectedBidResponses": [ { "currency": "USD", @@ -112,6 +131,9 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", + "adomain": ["insticator.com"], + "cat": ["IAB1-1"], + "dur": 30, "crid": "crid_10", "w": 728, "mtype": 2, @@ -122,9 +144,19 @@ } } }, - "type": "video" + "BidMeta": { + "advertiserDomains": ["insticator.com"], + "mediaType": "video", + "primaryCatId": "IAB1-1" + }, + "BidVideo": { + "duration": 30, + "primary_category": "IAB1-1" + }, + "type": "video", + "seat": "insticator" } ] } ] -} +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/204.json b/adapters/insticator/insticatortest/supplemental/204.json index f0a43defb1..e2a7ef5787 100644 --- a/adapters/insticator/insticatortest/supplemental/204.json +++ b/adapters/insticator/insticatortest/supplemental/204.json @@ -1,71 +1,81 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id"] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 204, - "body": {} - } + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} } - ], - "expectedBidResponses": [] - } - \ No newline at end of file + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json b/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json index 0fcafa58b1..8d52f59282 100644 --- a/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json +++ b/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json @@ -1,77 +1,89 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-app-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-app-id", + "publisherId": "test-publisher-id" } } - ], - "app": { - "id": "test-app-id", - "bundle": "test-app.com" + } + ], + "app": { + "id": "test-app-id", + "bundle": "test-app.com" } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator-app.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-app-id", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "fake-app-id", + "publisherId": "test-publisher-id" } } - ], - "app": { + } + ], + "app": { "id": "test-app-id", "bundle": "test-app.com", - "publisher": { - "id": "test-publisher-id" - } + "publisher": { + "id": "test-publisher-id" } - }, - "impIDs":["test-imp-id"] + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [{ + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, @@ -82,39 +94,39 @@ "mediaType": "banner" } } - }] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/bad-imp-ext.json b/adapters/insticator/insticatortest/supplemental/bad-imp-ext.json index 2e0507791a..71727e03f4 100644 --- a/adapters/insticator/insticatortest/supplemental/bad-imp-ext.json +++ b/adapters/insticator/insticatortest/supplemental/bad-imp-ext.json @@ -1,29 +1,32 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": "invalid ext" - } - } - ], - "site": { - "publisher": { - "id": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": "invalid ext" } } - }, - - "expectedMakeRequestsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] - } - \ No newline at end of file + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/currency-conversion-fail.json b/adapters/insticator/insticatortest/supplemental/currency-conversion-fail.json index 4c7082f47d..1bdc9587da 100644 --- a/adapters/insticator/insticatortest/supplemental/currency-conversion-fail.json +++ b/adapters/insticator/insticatortest/supplemental/currency-conversion-fail.json @@ -1,49 +1,49 @@ { - "mockBidRequest": { - "cur": [ - "GBP" - ], - "id": "test-request-id", - "imp": [ + "mockBidRequest": { + "cur": [ + "GBP" + ], + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 728, - "h": 90 - } - ] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - }, - "bidfloor": 1, - "bidfloorcur": "GBP" - } - ], - "site": { - "publisher": { - "id": "test-publisher-id" + "w": 728, + "h": 90 } + ] }, "ext": { - "prebid": { - "currency": { - "rates": { - "INR": { - "USD": 2 - } - }, - "usepbsrates": false - } + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + }, + "bidfloor": 1, + "bidfloorcur": "GBP" + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "INR": { + "USD": 2 } + }, + "usepbsrates": false } - }, - "expectedMakeRequestsErrors": [ + } + } + }, + "expectedMakeRequestsErrors": [ { "value": "Error in converting the provided bid floor currency from GBP to USD", "comparison": "literal" diff --git a/adapters/insticator/insticatortest/supplemental/currency-conversion.json b/adapters/insticator/insticatortest/supplemental/currency-conversion.json index 9ce11dcdfb..61a6fa290d 100644 --- a/adapters/insticator/insticatortest/supplemental/currency-conversion.json +++ b/adapters/insticator/insticatortest/supplemental/currency-conversion.json @@ -1,152 +1,153 @@ { - "mockBidRequest": { - "cur": [ - "GBP" - ], - "id": "test-request-id", - "imp": [ + "mockBidRequest": { + "cur": [ + "GBP" + ], + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 728, - "h": 90 - } - ] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - }, - "bidfloor": 1, - "bidfloorcur": "GBP" - } - ], - "site": { - "publisher": { - "id": "test-publisher-id" + "w": 728, + "h": 90 } + ] }, "ext": { - "prebid": { - "currency": { - "rates": { - "GBP": { - "USD": 2 - } - }, - "usepbsrates": false - } + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + }, + "bidfloor": 1, + "bidfloorcur": "GBP" + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 } + }, + "usepbsrates": false } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "cur": [ - "GBP" - ], - "ext": { - "insticator": { - "caller": [ - { - "name": "Prebid-Server", - "version": "n/a" - } - ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 728, - "h": 90 - } - ] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - }, - "bidfloor": 2, - "bidfloorcur": "USD" - } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } - } - }, - "impIDs": [ - "test-imp-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "cur": [ + "GBP" + ], + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } ] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [ - { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.500000, - "adm": "some-test-ad", - "crid": "crid_10", - "h": 90, - "w": 728, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } - } - } - ] - } - ], - "cur": "USD" + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } + }, + "bidfloor": 2, + "bidfloorcur": "USD" } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } - } - }, - "type": "banner" + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } } - ] + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner", + "seat": "insticator" } - ] + ] + } + ] } \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/device-validation.json b/adapters/insticator/insticatortest/supplemental/device-validation.json index a493e1b28a..07a243f88b 100644 --- a/adapters/insticator/insticatortest/supplemental/device-validation.json +++ b/adapters/insticator/insticatortest/supplemental/device-validation.json @@ -56,7 +56,7 @@ "1.22.22.1" ] }, - "uri": "https://insticator.example.com/v1/pbs", + "uri": "https://insticator-app.example.com/v1/pbs?publisherId=test-publisher-id", "body": { "device": { "ip": "1.22.22.1" @@ -120,7 +120,7 @@ { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-vast-ad", "mtype": 2, "crid": "crid_10", @@ -160,7 +160,8 @@ } } }, - "type": "video" + "type": "video", + "seat": "insticator" } ] } diff --git a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json index 18fa069aed..d98a7eebaf 100644 --- a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json +++ b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json @@ -1,110 +1,137 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id1", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } - } + ] }, - { - "id": "test-imp-id2", - "video": { - "mimes": ["video/mp4"], - "minduration": 5, - "maxduration": 30, - "protocols": [2, 3, 5, 6], - "w": 640, - "h": 480 - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" + }, + { + "id": "test-imp-id2", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 5, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } } } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } } }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id1", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - } + { + "id": "test-imp-id2", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 5, + "maxduration": 30, + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 640, + "h": 480 }, - { - "id":"test-imp-id2", - "video": { - "mimes": ["video/mp4"], - "minduration": 5, - "maxduration": 30, - "protocols": [2, 3, 5, 6], - "w": 640, - "h": 480 - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id1", "test-imp-id2"] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [{ + "impIDs": [ + "test-imp-id1", + "test-imp-id2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id1", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, @@ -115,38 +142,39 @@ "mediaType": "banner" } } - }] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id1", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/request-ext-unmarshal-fail.json b/adapters/insticator/insticatortest/supplemental/request-ext-unmarshal-fail.json index 1ea883a11c..3a99a142a1 100644 --- a/adapters/insticator/insticatortest/supplemental/request-ext-unmarshal-fail.json +++ b/adapters/insticator/insticatortest/supplemental/request-ext-unmarshal-fail.json @@ -1,17 +1,24 @@ { -"mockBidRequest": { + "mockBidRequest": { "id": "test-request-id", "imp": [ { "id": "test-imp-id", "video": { - "w": 728, + "w": 728, "h": 90, - "protocols": [2], + "protocols": [ + 2 + ], "placement": 1, "startdelay": -2, - "playbackmethod": [2], - "mimes": ["foo", "bar"] + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] }, "ext": { "bidder": "invalid" @@ -24,18 +31,17 @@ } }, "ext": { - "insticator": "invalid" + "insticator": "invalid" } }, - - "expectedMakeRequestsErrors": [ - { - "value": "cannot unmarshal insticator.reqExt.Insticator: expect { or n, but found \"", - "comparison": "literal" - }, - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] + "expectedMakeRequestsErrors": [ + { + "value": "cannot unmarshal insticator.reqExt.Insticator: expect { or n, but found \"", + "comparison": "literal" + }, + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] } \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/response-unmarshal-fail.json b/adapters/insticator/insticatortest/supplemental/response-unmarshal-fail.json index a3b40b084e..7ae1059b9c 100644 --- a/adapters/insticator/insticatortest/supplemental/response-unmarshal-fail.json +++ b/adapters/insticator/insticatortest/supplemental/response-unmarshal-fail.json @@ -1,102 +1,102 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [ + 2 + ], + "placement": 1, + "startdelay": -2, + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ { - "id": "test-imp-id", - "video": { - "w": 728, - "h": 90, - "protocols": [ - 2 - ], - "placement": 1, - "startdelay": -2, - "playbackmethod": [ - 2 - ], - "mimes": [ - "foo", - "bar" - ] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [ + 2 + ], + "placement": 1, + "startdelay": -2, + "playbackmethod": [ + 2 + ], + "mimes": [ + "foo", + "bar" + ] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } + } } - ], - "site": { + ], + "site": { "publisher": { - "id": "test-publisher-id" + "id": "test-publisher-id" } - } - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ - { - "name": "Prebid-Server", - "version": "n/a" - } - ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 728, - "h": 90, - "protocols": [ - 2 - ], - "placement": 1, - "startdelay": -2, - "playbackmethod": [ - 2 - ], - "mimes": [ - "foo", - "bar" - ] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - } - } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } - } - }, - "impIDs": [ - "test-imp-id" - ] - }, - "mockResponse": { - "status": 200, - "body": "invalid json" - } - } - ], - "expectedMakeBidsErrors": [ - { - "value": "expect { or n, but found \"", - "comparison": "literal" - } - ] + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid json" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] } \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json b/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json index 00c694a197..74782b966e 100644 --- a/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json +++ b/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json @@ -1,77 +1,89 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "id": "test-site-id", - "domain": "test-site.com" + } + ], + "site": { + "id": "test-site-id", + "domain": "test-site.com" } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { + } + ], + "site": { "id": "test-site-id", "domain": "test-site.com", - "publisher": { - "id": "test-publisher-id" - } + "publisher": { + "id": "test-publisher-id" } - }, - "impIDs":["test-imp-id"] + } }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "seat": "insticator", - "bid": [{ + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", "impid": "test-imp-id", - "price": 0.500000, + "price": 0.5, "adm": "some-test-ad", "crid": "crid_10", "h": 90, @@ -82,39 +94,39 @@ "mediaType": "banner" } } - }] - } - ], - "cur": "USD" - } + } + ] + } + ], + "cur": "USD" } } - ], - - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", - "impid": "test-imp-id", - "price": 0.5, - "adm": "some-test-ad", - "crid": "crid_10", - "w": 728, - "h": 90, - "mtype": 1, - "ext": { - "insticator": { - "mediaType": "banner" - } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" } - }, - "type": "banner" - } - ] - } - ] - } - \ No newline at end of file + } + }, + "type": "banner", + "seat": "insticator" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/status-not-ok.json b/adapters/insticator/insticatortest/supplemental/status-not-ok.json index e530896e2d..374b2bca26 100644 --- a/adapters/insticator/insticatortest/supplemental/status-not-ok.json +++ b/adapters/insticator/insticatortest/supplemental/status-not-ok.json @@ -1,86 +1,95 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "bidder": { - "adUnitId": "fake-invalid-site-id", - "publisherId": "test-publisher-id" + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 } + ] + }, + "ext": { + "bidder": { + "adUnitId": "fake-invalid-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://insticator.example.com/v1/pbs", - "body": { - "ext": { - "insticator": { - "caller": [ + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://insticator.example.com/v1/pbs?publisherId=test-publisher-id", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "name": "Prebid-Server", - "version": "n/a" + "w": 728, + "h": 90 } ] - } - }, - "id": "test-request-id", - "imp": [ - { - "id":"test-imp-id", - "banner": { - "format": [{"w": 728, "h": 90}] - }, - "ext": { - "insticator": { - "adUnitId": "fake-invalid-site-id", - "publisherId": "test-publisher-id" - } + }, + "ext": { + "insticator": { + "adUnitId": "fake-invalid-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - "impIDs":["test-imp-id"] - }, - "mockResponse": { - "status": 400, - "body": { - "error": { - "message": "Validation failed", - "details": [ - { - "message": "site.id is invalid" - } - ] + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 400, + "body": { + "error": { + "message": "Validation failed", + "details": [ + { + "message": "site.id is invalid" + } + ] } } } - ], - - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] - } - \ No newline at end of file + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/video-validation-fail.json b/adapters/insticator/insticatortest/supplemental/video-validation-fail.json index 553b0f68c6..51f40f8333 100644 --- a/adapters/insticator/insticatortest/supplemental/video-validation-fail.json +++ b/adapters/insticator/insticatortest/supplemental/video-validation-fail.json @@ -1,33 +1,31 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "video": { - "w": 728, - "h": 90 - }, - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" } } - ], - "site": { - "publisher": { - "id": "test-publisher-id" - } } - }, - - "expectedMakeRequestsErrors": [ - { - "value": "One or more invalid or missing video field(s) w, h, mimes", - "comparison": "literal" + ], + "site": { + "publisher": { + "id": "test-publisher-id" } - ] - } - \ No newline at end of file + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "One or more invalid or missing video field(s) w, h, mimes", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/static/bidder-info/insticator.yaml b/static/bidder-info/insticator.yaml index 907ff4a50d..adef8536d6 100644 --- a/static/bidder-info/insticator.yaml +++ b/static/bidder-info/insticator.yaml @@ -1,7 +1,11 @@ endpoint: "https://ex.ingage.tech/v1/prebidserver" +extra_info: '{"app_endpoint":"https://aex.ingage.tech/v1/prebidserver"}' +endpointCompression: GZIP maintainer: email: "prebid@insticator.com" gvlVendorID: 910 +openrtb: + version: "2.6" capabilities: app: mediaTypes: diff --git a/static/bidder-params/insticator.json b/static/bidder-params/insticator.json index 358ec37f57..7e6f8d635d 100644 --- a/static/bidder-params/insticator.json +++ b/static/bidder-params/insticator.json @@ -3,7 +3,7 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Insticator Adapter Params", "description": "A schema which validates params accepted by Insticator", - + "type": "object", "properties": { "adUnitId": { From b9da50d81c7c3a71211ee0a1faafd97d5852c948 Mon Sep 17 00:00:00 2001 From: Gabriel Mougard <gabriel.mougard@gmail.com> Date: Tue, 3 Mar 2026 15:41:45 +0100 Subject: [PATCH 175/272] Mobkoi: Always set TagID with placementID (#4644) --- adapters/mobkoi/mobkoi.go | 12 +- .../placement-id-overrides-tagid.json | 146 ++++++++++++++++++ 2 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 adapters/mobkoi/mobkoitest/exemplary/placement-id-overrides-tagid.json diff --git a/adapters/mobkoi/mobkoi.go b/adapters/mobkoi/mobkoi.go index 3f8bffe0c5..902616dd3f 100644 --- a/adapters/mobkoi/mobkoi.go +++ b/adapters/mobkoi/mobkoi.go @@ -37,13 +37,11 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte return nil, []error{err} } - if request.Imp[0].TagID == "" { - if ext.Bidder.PlacementID != "" { - request.Imp[0].TagID = ext.Bidder.PlacementID - } else { - return nil, []error{ - errors.New("invalid because it comes with neither request.imp[0].tagId nor req.imp[0].ext.Bidder.placementId"), - } + if ext.Bidder.PlacementID != "" { + request.Imp[0].TagID = ext.Bidder.PlacementID + } else if request.Imp[0].TagID == "" { + return nil, []error{ + errors.New("invalid because it comes with neither request.imp[0].tagId nor req.imp[0].ext.Bidder.placementId"), } } diff --git a/adapters/mobkoi/mobkoitest/exemplary/placement-id-overrides-tagid.json b/adapters/mobkoi/mobkoitest/exemplary/placement-id-overrides-tagid.json new file mode 100644 index 0000000000..99e6f64c46 --- /dev/null +++ b/adapters/mobkoi/mobkoitest/exemplary/placement-id-overrides-tagid.json @@ -0,0 +1,146 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user", + "consent": "consent-string" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id1", + "tagid": "originalTagId", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "placementId": "placementId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://dev.mobkoi.com/bid", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id1", + "tagid": "placementId", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "placementId": "placementId" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user", + "consent": "consent-string", + "ext": { + "consent": "consent-string" + } + }, + "tmax": 1000 + }, + "impIDs": [ + "some-impression-id1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50, + "lurl": "mobkoi/loss", + "nurl": "mobkoi/win" + } + ], + "type": "banner", + "seat": "mobkoi" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id1", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "lurl": "mobkoi/loss", + "nurl": "mobkoi/win" + }, + "type": "banner", + "seat": "mobkoi" + } + ] + } + ] +} \ No newline at end of file From c3a6f51aa208530ca6826b03cb6e8bd0982d992d Mon Sep 17 00:00:00 2001 From: quietPusher <129727954+quietPusher@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:52:30 +0100 Subject: [PATCH 176/272] New Limelight Adapters (#4651) Co-authored-by: apykhteyev <alex@project-limelight.com> Co-authored-by: mderevyanko <mderevyanko24@gmail.com> --- static/bidder-info/altstar.yaml | 2 ++ static/bidder-info/anzuExchange.yaml | 2 ++ static/bidder-info/oveeo.yaml | 2 ++ static/bidder-info/rtbdemand.yaml | 2 ++ static/bidder-info/smootai.yaml | 2 ++ 5 files changed, 10 insertions(+) create mode 100644 static/bidder-info/altstar.yaml create mode 100644 static/bidder-info/anzuExchange.yaml create mode 100644 static/bidder-info/oveeo.yaml create mode 100644 static/bidder-info/rtbdemand.yaml create mode 100644 static/bidder-info/smootai.yaml diff --git a/static/bidder-info/altstar.yaml b/static/bidder-info/altstar.yaml new file mode 100644 index 0000000000..1e8826ffb7 --- /dev/null +++ b/static/bidder-info/altstar.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.ads-altstarmedia.com/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" \ No newline at end of file diff --git a/static/bidder-info/anzuExchange.yaml b/static/bidder-info/anzuExchange.yaml new file mode 100644 index 0000000000..ae50ef3e7f --- /dev/null +++ b/static/bidder-info/anzuExchange.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.marketplace-anzu.io/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" \ No newline at end of file diff --git a/static/bidder-info/oveeo.yaml b/static/bidder-info/oveeo.yaml new file mode 100644 index 0000000000..388fea5ed6 --- /dev/null +++ b/static/bidder-info/oveeo.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.rtb-oveeo.com/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" \ No newline at end of file diff --git a/static/bidder-info/rtbdemand.yaml b/static/bidder-info/rtbdemand.yaml new file mode 100644 index 0000000000..9f3edf6d48 --- /dev/null +++ b/static/bidder-info/rtbdemand.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.ads-rtbdemand.com/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" \ No newline at end of file diff --git a/static/bidder-info/smootai.yaml b/static/bidder-info/smootai.yaml new file mode 100644 index 0000000000..4185dc0478 --- /dev/null +++ b/static/bidder-info/smootai.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.ads-smoot.com/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" \ No newline at end of file From 057f03a0537d48a40b68072eded6b4cf0d55dd39 Mon Sep 17 00:00:00 2001 From: Alexandre <101182841+mediasquare-alexandre@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:29:01 +0100 Subject: [PATCH 177/272] Mediasquare: Add user sync & site capabilities (#4589) --- adapters/mediasquare/mediasquare.go | 2 - .../exemplary/multi-format.json | 103 +++++++++++++----- .../exemplary/simple-banner.json | 15 ++- .../exemplary/simple-native.json | 18 ++- .../exemplary/simple-video.json | 15 ++- .../supplemental/no-valid-imp-ext.json | 7 +- .../supplemental/no-valid-response.json | 18 +-- .../supplemental/status-400.json | 10 +- .../supplemental/status-not-200.json | 10 +- adapters/mediasquare/parsers.go | 17 ++- adapters/mediasquare/structs.go | 36 ++++-- adapters/mediasquare/utils.go | 6 +- static/bidder-info/mediasquare.yaml | 9 ++ 13 files changed, 191 insertions(+), 75 deletions(-) diff --git a/adapters/mediasquare/mediasquare.go b/adapters/mediasquare/mediasquare.go index c23164c254..4a7943d058 100644 --- a/adapters/mediasquare/mediasquare.go +++ b/adapters/mediasquare/mediasquare.go @@ -33,7 +33,6 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } msqParams := initMsqParams(request) - msqParams.Test = (request.Test == int8(1)) for _, imp := range request.Imp { var ( bidderExt adapters.ExtImpBidder @@ -88,7 +87,6 @@ func (a *adapter) makeRequest(request *openrtb2.BidRequest, msqParams *msqParame } else { err = errorWriter("<makeRequest> jsonutil.Marshal", err, false) } - return } diff --git a/adapters/mediasquare/mediasquaretest/exemplary/multi-format.json b/adapters/mediasquare/mediasquaretest/exemplary/multi-format.json index 335da6ab6c..ba89936eaf 100644 --- a/adapters/mediasquare/mediasquaretest/exemplary/multi-format.json +++ b/adapters/mediasquare/mediasquaretest/exemplary/multi-format.json @@ -126,14 +126,21 @@ "language": "fr", "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" }, + "site": { + "id": "test-site-id", + "page": "https://www.example.com/" + }, "regs": { "gdpr": 1, "ext": { - "dsa": "mediasquare-test" + "dsa": { + "msq_test": 42 + } } }, "user": { - "consent": "there-is-a-real-cs-in-it" + "consent": "there-is-a-real-cs-in-it", + "buyeruid": "42" }, "test": 1 }, @@ -237,7 +244,10 @@ "consent_required": true, "consent_string": "there-is-a-real-cs-in-it" }, - "dsa": "mediasquare-test", + "dsa": { + "msq_test": 42 + }, + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -257,10 +267,19 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "site": { + "id": "test-site-id", + "page": "https://www.example.com/" + }, + "user": { + "consent": "there-is-a-real-cs-in-it", + "buyeruid": "42" } }, "type": "pbs", - "test": true + "test": true, + "user_uid": "42" }, "impIDs": [ "2c35e25e-e7d3-41bf-b810-06a449f456b9", @@ -293,7 +312,12 @@ "transaction_id": "2c35e25e-e7d3-41bf-b810-06a449f456b9", "ttl": 20000, "adomain": ["mediasquare.fr"], - "hasConsent": true + "hasConsent": true, + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } }, { "ad": "\u003c!-- This is an example --\u003e", @@ -309,7 +333,12 @@ "transaction_id": "2059a3e6-71a3-43ea-8290-b5ceb13d35a8", "ttl": 20000, "adomain": ["mediasquare.fr"], - "hasConsent": true + "hasConsent": true, + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } }, { "bid_id": "2c35e25e-e7d3-41bf-b810-06a449f456c9", @@ -327,7 +356,12 @@ "title": "Learn about this awesome thing" }, "adomain": ["mediasquare.fr"], - "hasConsent": true + "hasConsent": true, + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } }, { "bid_id": "2c35e25e-e7d3-41bf-b810-06a449f456d9", @@ -345,27 +379,14 @@ "url": "https://dummy.domain.tv/some_vast" }, "adomain": ["mediasquare.fr"], - "hasConsent": true - } - ], - "Calc_cpm": { - "2059a3e6-71a3-43ea-8290-b5ceb13d35a8": { - "TmpCpmMax": 0, - "CpmMax": 0.02 - }, - "2c35e25e-e7d3-41bf-b810-06a449f456b9": { - "TmpCpmMax": 0, - "CpmMax": 2 - }, - "2c35e25e-e7d3-41bf-b810-06a449f456c9": { - "TmpCpmMax": 0, - "CpmMax": 2 - }, - "2c35e25e-e7d3-41bf-b810-06a449f456d9": { - "TmpCpmMax": 0, - "CpmMax": 2 + "hasConsent": true, + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } } - } + ] } } } @@ -382,6 +403,13 @@ "adm": "\u003c!-- This is an example --\u003e", "adomain": ["mediasquare.fr"], "crid": "msq_test|fakeCreative", + "ext": { + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } + }, "w": 250, "mtype": 1 }, @@ -399,6 +427,13 @@ "adm": "\u003c!-- This is an example --\u003e", "adomain": ["mediasquare.fr"], "crid": "msq_test|fakeCreative", + "ext": { + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } + }, "w": 250, "mtype": 1 }, @@ -415,6 +450,13 @@ "price": 2, "adomain": ["mediasquare.fr"], "crid": "msq_test|fakeCreative", + "ext": { + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } + }, "mtype": 4 }, "BidMeta": { @@ -430,6 +472,13 @@ "price": 2, "adomain": ["mediasquare.fr"], "crid": "msq_test|fakeCreative", + "ext": { + "dsa": { + "adrender": 1, + "behalf": "test-behalf", + "paid": "test-paid" + } + }, "mtype": 2 }, "BidMeta": { diff --git a/adapters/mediasquare/mediasquaretest/exemplary/simple-banner.json b/adapters/mediasquare/mediasquaretest/exemplary/simple-banner.json index 8769b37df1..5753abb611 100644 --- a/adapters/mediasquare/mediasquaretest/exemplary/simple-banner.json +++ b/adapters/mediasquare/mediasquaretest/exemplary/simple-banner.json @@ -58,7 +58,9 @@ "regs": { "gdpr": 1, "ext": { - "dsa": "mediasquare-test" + "dsa": { + "msq_test": 42 + } } }, "user": { @@ -126,7 +128,10 @@ "consent_required": true, "consent_string": "there-is-a-real-cs-in-it" }, - "dsa": "mediasquare-test", + "dsa": { + "msq_test": 42 + }, + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -146,10 +151,14 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "user": { + "consent": "there-is-a-real-cs-in-it" } }, "type": "pbs", - "test": true + "test": true, + "user_uid": "" }, "impIDs": [ "2c35e25e-e7d3-41bf-b810-06a449f456b9", diff --git a/adapters/mediasquare/mediasquaretest/exemplary/simple-native.json b/adapters/mediasquare/mediasquaretest/exemplary/simple-native.json index 9a9e842b34..23d29d544b 100644 --- a/adapters/mediasquare/mediasquaretest/exemplary/simple-native.json +++ b/adapters/mediasquare/mediasquaretest/exemplary/simple-native.json @@ -42,13 +42,16 @@ "regs": { "gdpr": 1, "ext": { - "dsa": "mediasquare-test" + "dsa": { + "msq_test": 42 + } } }, "user": { "consent": "there-is-a-real-cs-in-it" }, - "test": 1 + "test": 1, + "user_uid": "" }, "httpCalls": [ @@ -76,7 +79,10 @@ "consent_required": true }, "type": "pbs", - "dsa": "mediasquare-test", + "dsa": { + "msq_test": 42 + }, + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -96,9 +102,13 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "user": { + "consent": "there-is-a-real-cs-in-it" } }, - "test": true + "test": true, + "user_uid": "" }, "impIDs": ["2c35e25e-e7d3-41bf-b810-06a449f456b9"] }, diff --git a/adapters/mediasquare/mediasquaretest/exemplary/simple-video.json b/adapters/mediasquare/mediasquaretest/exemplary/simple-video.json index 13de7f873b..bd00984ad7 100644 --- a/adapters/mediasquare/mediasquaretest/exemplary/simple-video.json +++ b/adapters/mediasquare/mediasquaretest/exemplary/simple-video.json @@ -52,7 +52,9 @@ "regs": { "gdpr": 1, "ext": { - "dsa": "mediasquare-test" + "dsa": { + "msq_test": 42 + } } }, "user": { @@ -100,7 +102,10 @@ "consent_required": true }, "type": "pbs", - "dsa": "mediasquare-test", + "dsa": { + "msq_test": 42 + }, + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -120,9 +125,13 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "user": { + "consent": "there-is-a-real-cs-in-it" } }, - "test": true + "test": true, + "user_uid": "" }, "impIDs": ["2c35e25e-e7d3-41bf-b810-06a449f456b9"] }, diff --git a/adapters/mediasquare/mediasquaretest/supplemental/no-valid-imp-ext.json b/adapters/mediasquare/mediasquaretest/supplemental/no-valid-imp-ext.json index 6fae03fd4e..3c43f93784 100644 --- a/adapters/mediasquare/mediasquaretest/supplemental/no-valid-imp-ext.json +++ b/adapters/mediasquare/mediasquaretest/supplemental/no-valid-imp-ext.json @@ -51,9 +51,10 @@ "codes": null, "gdpr": { "consent_required": false, "consent_string": "" }, "type": "pbs", - "dsa": "", - "tech": { "device": null, "app": null }, - "test": true + "pbjs": "prebid-test-version", + "tech": {}, + "test": true, + "user_uid": "" }, "impIDs": ["0", "1", "-42", "-1", "-0", "42"] }, diff --git a/adapters/mediasquare/mediasquaretest/supplemental/no-valid-response.json b/adapters/mediasquare/mediasquaretest/supplemental/no-valid-response.json index 5e987db615..ce2eec4eec 100644 --- a/adapters/mediasquare/mediasquaretest/supplemental/no-valid-response.json +++ b/adapters/mediasquare/mediasquaretest/supplemental/no-valid-response.json @@ -26,6 +26,7 @@ ], "app": null, "device": null, + "site": null, "regs": { "gdpr": null, "ext": { @@ -51,17 +52,18 @@ "uri": "https://pbs-front.mediasquare.fr/msq_prebid", "body": { "codes": null, - "gdpr": { - "consent_string": "", - "consent_required": false - }, + "gdpr": { "consent_required": false, "consent_string": "" }, "type": "pbs", - "dsa": "", + "pbjs": "prebid-test-version", "tech": { - "device": null, - "app": null + "user": { + "ext": { + "consent": null + } + } }, - "test": true + "test": true, + "user_uid": "" }, "impIDs": ["2c35e25e-e7d3-41bf-b810-06a449f456b9"] }, diff --git a/adapters/mediasquare/mediasquaretest/supplemental/status-400.json b/adapters/mediasquare/mediasquaretest/supplemental/status-400.json index 05e4413a97..0541a0fdd8 100644 --- a/adapters/mediasquare/mediasquaretest/supplemental/status-400.json +++ b/adapters/mediasquare/mediasquaretest/supplemental/status-400.json @@ -102,7 +102,7 @@ "consent_required": true }, "type": "pbs", - "dsa": "", + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -122,9 +122,15 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "user": { + "ext": { + "consent": "consent-covering" + } } }, - "test": true + "test": true, + "user_uid": "" }, "impIDs": ["2c35e25e-e7d3-41bf-b810-06a449f456b9"] }, diff --git a/adapters/mediasquare/mediasquaretest/supplemental/status-not-200.json b/adapters/mediasquare/mediasquaretest/supplemental/status-not-200.json index 4168a7adea..f2e91c9581 100644 --- a/adapters/mediasquare/mediasquaretest/supplemental/status-not-200.json +++ b/adapters/mediasquare/mediasquaretest/supplemental/status-not-200.json @@ -102,7 +102,7 @@ "consent_required": true }, "type": "pbs", - "dsa": "", + "pbjs": "prebid-test-version", "tech": { "device": { "geo": { @@ -122,9 +122,15 @@ "id": "MEDIA_SQUARE" }, "content": {} + }, + "user": { + "ext": { + "gdpr": "consent-covering" + } } }, - "test": true + "test": true, + "user_uid": "" }, "impIDs": ["2c35e25e-e7d3-41bf-b810-06a449f456b9"] }, diff --git a/adapters/mediasquare/parsers.go b/adapters/mediasquare/parsers.go index f2ef4ab675..6e7dcfa86b 100644 --- a/adapters/mediasquare/parsers.go +++ b/adapters/mediasquare/parsers.go @@ -24,15 +24,14 @@ func (parser *parserDSA) setContent(extJsonBytes []byte) error { } // getValue: Returns the DSA value as a string, defaultly returns empty-string. -func (parser parserDSA) getValue(request *openrtb2.BidRequest) (dsa string) { +func (parser parserDSA) getValue(request *openrtb2.BidRequest) interface{} { if request == nil || request.Regs == nil { - return + return nil } - parser.setContent(request.Regs.Ext) - if parser.DSA != nil { - dsa = fmt.Sprint(parser.DSA) + if parser.setContent(request.Regs.Ext) != nil { + return nil } - return + return parser.DSA } // parserGDPR: Struct used to extract pair of GDPR/Consent of a jsonutil. @@ -68,9 +67,9 @@ func (parser parserGDPR) getValue(field string, request *openrtb2.BidRequest) (g if request != nil { switch { case field == "consent_requirement" && request.Regs != nil: - gdpr = "false" - if ptrInt8ToBool(request.Regs.GDPR) { - gdpr = "true" + gdpr = "true" + if !ptrInt8ToBool(request.Regs.GDPR) { + gdpr = "false" } case field == "consent_string" && request.User != nil: gdpr = request.User.Consent diff --git a/adapters/mediasquare/structs.go b/adapters/mediasquare/structs.go index 3758e31380..23e15f4068 100644 --- a/adapters/mediasquare/structs.go +++ b/adapters/mediasquare/structs.go @@ -6,6 +6,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v3/version" ) // msqResponse: Bid-Response sent by mediasquare. @@ -20,12 +21,14 @@ type msqResponse struct { // msqParameters: Bid-Request sent to mediasquare. type msqParameters struct { - Codes []msqParametersCodes `json:"codes"` - Gdpr msqParametersGdpr `json:"gdpr"` - Type string `json:"type"` - DSA interface{} `json:"dsa,omitempty"` - Support msqSupport `json:"tech"` - Test bool `json:"test"` + Codes []msqParametersCodes `json:"codes"` + Gdpr msqParametersGdpr `json:"gdpr"` + Type string `json:"type"` + PrebidVer string `json:"pbjs,omitempty"` + DSA interface{} `json:"dsa,omitempty"` + Support msqSupport `json:"tech"` + Test bool `json:"test"` + UserUID string `json:"user_uid"` } type msqResponseBidsVideo struct { @@ -83,8 +86,10 @@ type msqResponseBids struct { } type msqSupport struct { - Device interface{} `json:"device"` - App interface{} `json:"app"` + Device *openrtb2.Device `json:"device,omitempty"` + App *openrtb2.App `json:"app,omitempty"` + Site *openrtb2.Site `json:"site,omitempty"` + User *openrtb2.User `json:"user,omitempty"` } type msqParametersCodes struct { @@ -122,13 +127,26 @@ func initMsqParams(request *openrtb2.BidRequest) (msqParams msqParameters) { msqParams.Support = msqSupport{ Device: request.Device, App: request.App, + Site: request.Site, + User: request.User, } msqParams.Gdpr = msqParametersGdpr{ ConsentRequired: (parserGDPR{}).getValue("consent_requirement", request) == "true", ConsentString: (parserGDPR{}).getValue("consent_string", request), } msqParams.DSA = (parserDSA{}).getValue(request) - + if request.User != nil && len(request.User.BuyerUID) > 0 { + msqParams.UserUID = request.User.BuyerUID + } + msqParams.Test = (request.Test == int8(1)) + switch { + case msqParams.Test: + msqParams.PrebidVer = "prebid-test-version" + case len(version.Ver) > 0: + msqParams.PrebidVer = version.Ver + default: + msqParams.PrebidVer = "n/a" + } return } diff --git a/adapters/mediasquare/utils.go b/adapters/mediasquare/utils.go index 50ee7285a7..77e6bb9daf 100644 --- a/adapters/mediasquare/utils.go +++ b/adapters/mediasquare/utils.go @@ -87,9 +87,9 @@ func ptrInt8ToBool(i *int8) bool { } // errorWriter: Returns a Custom error message. -func errorWriter(referer string, err error, isEmpty bool) error { +func errorWriter(header string, err error, isEmpty bool) error { if isEmpty { - return fmt.Errorf("%s: is empty.", referer) + return fmt.Errorf("%s: is empty.", header) } - return fmt.Errorf("%s: %s", referer, err.Error()) + return fmt.Errorf("%s: %s", header, err.Error()) } diff --git a/static/bidder-info/mediasquare.yaml b/static/bidder-info/mediasquare.yaml index b6d21f4c9f..8a5730c509 100644 --- a/static/bidder-info/mediasquare.yaml +++ b/static/bidder-info/mediasquare.yaml @@ -10,3 +10,12 @@ capabilities: - banner - video - native + site: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: https://pbs-front.mediasquare.fr/sync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID From 15b40f377e695ad34c8c6b80ee3733c0e6c6dbb4 Mon Sep 17 00:00:00 2001 From: Jean BOUDET <jboudet+dev@protonmail.com> Date: Tue, 3 Mar 2026 21:19:08 +0100 Subject: [PATCH 178/272] New adapter: BeOp (#4660) --- adapters/beop/beop.go | 172 ++++++++++++++++++ adapters/beop/beop_test.go | 21 +++ .../exemplary/banner-web-with-nid.json | 155 ++++++++++++++++ .../beop/beoptest/exemplary/banner-web.json | 153 ++++++++++++++++ .../beop/beoptest/exemplary/video-web.json | 163 +++++++++++++++++ .../supplemental/empty-seatbid-array.json | 111 +++++++++++ .../supplemental/invalid-bid-type.json | 131 +++++++++++++ .../supplemental/invalid-response.json | 104 +++++++++++ .../supplemental/missing-bidder-params.json | 41 +++++ .../supplemental/status-code-bad-request.json | 104 +++++++++++ .../supplemental/status-code-no-content.json | 98 ++++++++++ .../status-code-service-unavailable.json | 104 +++++++++++ adapters/beop/params_test.go | 49 +++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_beop.go | 7 + static/bidder-info/beop.yaml | 12 ++ static/bidder-params/beop.json | 33 ++++ 18 files changed, 1462 insertions(+) create mode 100644 adapters/beop/beop.go create mode 100644 adapters/beop/beop_test.go create mode 100644 adapters/beop/beoptest/exemplary/banner-web-with-nid.json create mode 100644 adapters/beop/beoptest/exemplary/banner-web.json create mode 100644 adapters/beop/beoptest/exemplary/video-web.json create mode 100644 adapters/beop/beoptest/supplemental/empty-seatbid-array.json create mode 100644 adapters/beop/beoptest/supplemental/invalid-bid-type.json create mode 100644 adapters/beop/beoptest/supplemental/invalid-response.json create mode 100644 adapters/beop/beoptest/supplemental/missing-bidder-params.json create mode 100644 adapters/beop/beoptest/supplemental/status-code-bad-request.json create mode 100644 adapters/beop/beoptest/supplemental/status-code-no-content.json create mode 100644 adapters/beop/beoptest/supplemental/status-code-service-unavailable.json create mode 100644 adapters/beop/params_test.go create mode 100644 openrtb_ext/imp_beop.go create mode 100644 static/bidder-info/beop.yaml create mode 100644 static/bidder-params/beop.json diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go new file mode 100644 index 0000000000..ffbb4c94bd --- /dev/null +++ b/adapters/beop/beop.go @@ -0,0 +1,172 @@ +package beop + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder( + bidderName openrtb_ext.BidderName, + config config.Adapter, + server config.Server) ( + adapters.Bidder, error, +) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) getRequestExtImpBeop(imp *openrtb2.Imp) (*openrtb_ext.ExtImpBeop, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + var beopExt openrtb_ext.ExtImpBeop + if err := jsonutil.Unmarshal(bidderExt.Bidder, &beopExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + return &beopExt, nil +} + +func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpBeop) (string, error) { + url, _ := url.Parse(a.endpoint) + query := url.Query() + if pid := params.BeopPublisherID; len(pid) != 0 { + query.Set("pid", pid) + } + if nid := params.BeopNetworkID; len(nid) != 0 { + query.Set("nid", nid) + } + if nptnid := params.BeopNetworkPartnerID; len(nptnid) != 0 { + query.Set("nptnid", nptnid) + } + url.RawQuery = query.Encode() + return url.String(), nil +} + +func (a *adapter) MakeRequests( + request *openrtb2.BidRequest, + requestInfo *adapters.ExtraRequestInfo) ( + []*adapters.RequestData, []error, +) { + var beopExt *openrtb_ext.ExtImpBeop + var err error + + beopExt, err = a.getRequestExtImpBeop(&request.Imp[0]) + if err != nil { + return nil, []error{err} + } + + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + url, err := a.buildEndpointURL(beopExt) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: url, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + mType := bid.MType + var bidType openrtb_ext.BidType + switch mType { + case openrtb2.MarkupBanner: + bidType = openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + bidType = openrtb_ext.BidTypeVideo + default: + return bidType, fmt.Errorf("Failed to parse bid mType for impression \"%s\"", bid.ImpID) + } + return bidType, nil +} + +func (a *adapter) MakeBids( + request *openrtb2.BidRequest, + requestData *adapters.RequestData, + responseData *adapters.ResponseData) ( + *adapters.BidderResponse, []error, +) { + if responseData.StatusCode == http.StatusNoContent { + return nil, nil + } + + if responseData.StatusCode == http.StatusServiceUnavailable { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Service Unavailable. Status Code: [ %d ] ", responseData.StatusCode), + }} + } + + if responseData.StatusCode == http.StatusBadRequest { + err := &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + var responseBody openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &responseBody); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + if len(responseBody.SeatBid) == 0 { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Empty SeatBid array", + }} + } + + bidResponseFinal := adapters.NewBidderResponseWithBidsCapacity(len(responseBody.SeatBid[0].Bid)) + seatBid := responseBody.SeatBid[0] + var errors []error + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bidResponseFinal.Bids = append(bidResponseFinal.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + if len(bidResponseFinal.Bids) == 0 { + return nil, errors + } + return bidResponseFinal, errors +} diff --git a/adapters/beop/beop_test.go b/adapters/beop/beop_test.go new file mode 100644 index 0000000000..5960bc09f1 --- /dev/null +++ b/adapters/beop/beop_test.go @@ -0,0 +1,21 @@ +package beop + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBeop, config.Adapter{ + Endpoint: "http://hb-test.collectiveaudience.co/rtb/bid"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "beoptest", bidder) +} diff --git a/adapters/beop/beoptest/exemplary/banner-web-with-nid.json b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json new file mode 100644 index 0000000000..e0c6f9a880 --- /dev/null +++ b/adapters/beop/beoptest/exemplary/banner-web-with-nid.json @@ -0,0 +1,155 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", + "nptnid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?nid=aaaaaaaaaaaaaaaaaaaaaaaa&nptnid=1234", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", + "nptnid": "1234" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/exemplary/banner-web.json b/adapters/beop/beoptest/exemplary/banner-web.json new file mode 100644 index 0000000000..a757171e34 --- /dev/null +++ b/adapters/beop/beoptest/exemplary/banner-web.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/exemplary/video-web.json b/adapters/beop/beoptest/exemplary/video-web.json new file mode 100644 index 0000000000..bd4ff7acfe --- /dev/null +++ b/adapters/beop/beoptest/exemplary/video-web.json @@ -0,0 +1,163 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720, + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720, + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/empty-seatbid-array.json b/adapters/beop/beoptest/supplemental/empty-seatbid-array.json new file mode 100644 index 0000000000..0b709b2b93 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/empty-seatbid-array.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [] + } + } + } + ], + "mockResponse": { + "status": 200, + "body": "invalid response" + }, + "expectedMakeBidsErrors": [ + { + "value": "Empty SeatBid array", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/invalid-bid-type.json b/adapters/beop/beoptest/supplemental/invalid-bid-type.json new file mode 100644 index 0000000000..d0a8580963 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/invalid-bid-type.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 320, + "h": 50, + "mtype": 3, + "ext": { + "prebid": { + "type": "audio" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Failed to parse bid mType for impression \"impression-id\"", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/invalid-response.json b/adapters/beop/beoptest/supplemental/invalid-response.json new file mode 100644 index 0000000000..8c5537acef --- /dev/null +++ b/adapters/beop/beoptest/supplemental/invalid-response.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/missing-bidder-params.json b/adapters/beop/beoptest/supplemental/missing-bidder-params.json new file mode 100644 index 0000000000..4c2de07072 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/missing-bidder-params.json @@ -0,0 +1,41 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": {} + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "ext.bidder not provided", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/status-code-bad-request.json b/adapters/beop/beoptest/supplemental/status-code-bad-request.json new file mode 100644 index 0000000000..f8c0eb2d56 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-bad-request.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info.", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/beoptest/supplemental/status-code-no-content.json b/adapters/beop/beoptest/supplemental/status-code-no-content.json new file mode 100644 index 0000000000..25280c2395 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-no-content.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json b/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json new file mode 100644 index 0000000000..ce3742ab85 --- /dev/null +++ b/adapters/beop/beoptest/supplemental/status-code-service-unavailable.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://hb-test.collectiveaudience.co/rtb/bid?pid=aaaaaaaaaaaaaaaaaaaaaaaa", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "tid", + "ext": { + "bidder": { + "pid": "aaaaaaaaaaaaaaaaaaaaaaaa" + } + } + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + }, + "impIDs": [ + "impression-id" + ] + }, + "mockResponse": { + "status": 503 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Service Unavailable. Status Code: [ 503 ] ", + "comparison": "literal" + } + ] +} diff --git a/adapters/beop/params_test.go b/adapters/beop/params_test.go new file mode 100644 index 0000000000..5b854bd3af --- /dev/null +++ b/adapters/beop/params_test.go @@ -0,0 +1,49 @@ +package beop + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderBeop, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected adverxo params: %s", validParam) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderBeop, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{ "pid": "aaaaaaaaaaaaaaaaaaaaaaaa"}`, + `{ "nid": "aaaaaaaaaaaaaaaaaaaaaaaa", "ntpnid": "1234"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `{}`, + `{ "fid": 5 }`, + `{ "pid": 5 }`, + `{ "pid": 5 }`, + `{ "nid": "", "nptnid": "" }`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 96fdfd61fa..2d55c196b6 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -53,6 +53,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/beachfront" "github.com/prebid/prebid-server/v3/adapters/beintoo" "github.com/prebid/prebid-server/v3/adapters/bematterfull" + "github.com/prebid/prebid-server/v3/adapters/beop" "github.com/prebid/prebid-server/v3/adapters/between" "github.com/prebid/prebid-server/v3/adapters/beyondmedia" "github.com/prebid/prebid-server/v3/adapters/bidmachine" @@ -319,6 +320,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBeachfront: beachfront.Builder, openrtb_ext.BidderBeintoo: beintoo.Builder, openrtb_ext.BidderBematterfull: bematterfull.Builder, + openrtb_ext.BidderBeop: beop.Builder, openrtb_ext.BidderBetween: between.Builder, openrtb_ext.BidderBeyondMedia: beyondmedia.Builder, openrtb_ext.BidderBidmachine: bidmachine.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index de628a5dc4..9bb576fd52 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -69,6 +69,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderBeachfront, BidderBeintoo, BidderBematterfull, + BidderBeop, BidderBetween, BidderBeyondMedia, BidderBidmachine, @@ -442,6 +443,7 @@ const ( BidderBeachfront BidderName = "beachfront" BidderBeintoo BidderName = "beintoo" BidderBematterfull BidderName = "bematterfull" + BidderBeop BidderName = "beop" BidderBetween BidderName = "between" BidderBeyondMedia BidderName = "beyondmedia" BidderBidmachine BidderName = "bidmachine" diff --git a/openrtb_ext/imp_beop.go b/openrtb_ext/imp_beop.go new file mode 100644 index 0000000000..797ac92ef0 --- /dev/null +++ b/openrtb_ext/imp_beop.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpBeop struct { + BeopPublisherID string `json:"pid,omitempty"` + BeopNetworkID string `json:"nid,omitempty"` + BeopNetworkPartnerID string `json:"nptnid,omitempty"` +} diff --git a/static/bidder-info/beop.yaml b/static/bidder-info/beop.yaml new file mode 100644 index 0000000000..1129818f85 --- /dev/null +++ b/static/bidder-info/beop.yaml @@ -0,0 +1,12 @@ +endpoint: "https://hb.collectiveaudience.co/rtb/bid" +endpointCompression: gzip +maintainer: + email: tech@collectiveaudience.co +gvlVendorID: 666 +openrtb: + version: 2.6 +capabilities: + site: + mediaTypes: + - banner + - video diff --git a/static/bidder-params/beop.json b/static/bidder-params/beop.json new file mode 100644 index 0000000000..8b34ac91f7 --- /dev/null +++ b/static/bidder-params/beop.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "BeOp Adapter Params", + "description": "A schema which validates params accepted by the BeOp adapter", + "type": "object", + "properties": { + "pid": { + "type": "string", + "description": "Beop publisher ID" + }, + "nid": { + "type": "string", + "description": "Beop Network ID" + }, + "ntpnid": { + "type": "string", + "description": "Network partner ID" + } + }, + "oneOf": [ + { + "required": [ + "pid" + ] + }, + { + "required": [ + "nid", + "ntpnid" + ] + } + ] +} From 230d70bd8184e7e51a512f1fa1df17780d7be2bd Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Tue, 3 Mar 2026 22:28:48 +0200 Subject: [PATCH 179/272] New Adapter: Adastra - Attekmi Alias (#4607) --- static/bidder-info/adastra.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 static/bidder-info/adastra.yaml diff --git a/static/bidder-info/adastra.yaml b/static/bidder-info/adastra.yaml new file mode 100644 index 0000000000..2e06294181 --- /dev/null +++ b/static/bidder-info/adastra.yaml @@ -0,0 +1,5 @@ +endpoint: "https://adastra-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +aliasOf: "smarthub" +userSync: + supports: + - redirect \ No newline at end of file From ae886961d0f69035e133a06f9caa2f39144abe9b Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye <gabriel.chicoye@gmail.com> Date: Tue, 3 Mar 2026 21:42:22 +0100 Subject: [PATCH 180/272] Nexx360: Add gvlVendorID and update imp.ext field management (#4604) --- adapters/nexx360/nexx360.go | 22 ++- .../simple-banner-with-extra-ext.json | 133 ++++++++++++++++++ static/bidder-info/nexx360.yaml | 8 ++ 3 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 adapters/nexx360/nexx360test/exemplary/simple-banner-with-extra-ext.json diff --git a/adapters/nexx360/nexx360.go b/adapters/nexx360/nexx360.go index f91961918c..e69b375db2 100644 --- a/adapters/nexx360/nexx360.go +++ b/adapters/nexx360/nexx360.go @@ -66,11 +66,27 @@ func processImps(impList []openrtb2.Imp) (imp []openrtb2.Imp, tagId string, plac } } - impExt := Ext{ - Nexx360: bidderExt.Bidder, + // Unmarshal entire ext to preserve all fields + var impExtMap map[string]interface{} + if err := jsonutil.Unmarshal(imp.Ext, &impExtMap); err != nil { + return nil, "", "", &errortypes.BadInput{ + Message: err.Error(), + } } - impExtJSON, err := json.Marshal(impExt) + // Unmarshal nexx360 bidder params to a map for merging + var nexx360ExtMap map[string]interface{} + if err := jsonutil.Unmarshal(bidderExt.Bidder, &nexx360ExtMap); err != nil { + return nil, "", "", &errortypes.BadInput{ + Message: err.Error(), + } + } + + // Replace bidder field with nexx360 field + delete(impExtMap, "bidder") + impExtMap["nexx360"] = nexx360ExtMap + + impExtJSON, err := jsonutil.Marshal(impExtMap) if err != nil { return nil, "", "", &errortypes.BadInput{ Message: err.Error(), diff --git a/adapters/nexx360/nexx360test/exemplary/simple-banner-with-extra-ext.json b/adapters/nexx360/nexx360test/exemplary/simple-banner-with-extra-ext.json new file mode 100644 index 0000000000..704f8ebc6c --- /dev/null +++ b/adapters/nexx360/nexx360test/exemplary/simple-banner-with-extra-ext.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "tagId": "testnexx" + }, + "gpid": "/1111/homepage", + "ae": 1, + "data": { + "pbadslot": "homepage-top" + }, + "skadn": { + "version": "2.0", + "sourceapp": "123456789" + } + } + } + ], + "site": {}, + "ext": { + "nexx360": "Prebid-Server", + "test": 1 + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fast.nexx360.io/prebid-server?tag_id=testnexx", + "body": { + "ext": { + "nexx360": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "nexx360": { + "tagId": "testnexx" + }, + "gpid": "/1111/homepage", + "ae": 1, + "data": { + "pbadslot": "homepage-top" + }, + "skadn": { + "version": "2.0", + "sourceapp": "123456789" + } + } + } + ], + "site": {} + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "testalias", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-banner", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "mediaType": "banner", + "bidType": "banner", + "tagId": "testnexx", + "ssp": "test" + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/static/bidder-info/nexx360.yaml b/static/bidder-info/nexx360.yaml index 0a0b186ec9..c96b088fec 100644 --- a/static/bidder-info/nexx360.yaml +++ b/static/bidder-info/nexx360.yaml @@ -1,6 +1,7 @@ endpoint: "http://fast.nexx360.io/prebid-server" maintainer: email: "tech@nexx360.io" +gvlVendorID: 965 endpointCompression: gzip geoscope: - global @@ -17,3 +18,10 @@ capabilities: - video - native - audio +userSync: + redirect: + url: "https://fast.nexx360.io/usermatchredir/redirect?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gppsid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "$UID" + iframe: + url: "https://fast.nexx360.io/usermatchredir/iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gppsid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "$UID" From f601e3f3db83b21f6bab6abb4ca5d4197a65013e Mon Sep 17 00:00:00 2001 From: Pavel Ptashyts <49400901+pavel-ptashyts@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:32:04 +0100 Subject: [PATCH 181/272] New Adapter: ElementalTv (#4639) --- adapters/adoppler/adoppler_test.go | 20 ----- .../adopplertest/exemplary/custom-client.json | 81 ------------------- .../elementaltv.go} | 37 ++++----- adapters/elementaltv/elementaltv_test.go | 19 +++++ .../elementaltvtest/exemplary/base.json} | 2 +- .../elementaltvtest}/exemplary/multiimp.json | 6 +- .../supplemental/bad-request.json | 2 +- .../supplemental/duplicate-imp.json | 4 +- .../supplemental/invalid-impid.json | 2 +- .../supplemental/invalid-response.json | 2 +- .../supplemental/invalid-video-ext.json | 4 +- .../supplemental/missing-adunit.json | 2 +- .../elementaltvtest}/supplemental/no-bid.json | 2 +- .../supplemental/server-error.json | 2 +- adapters/elementaltv/params_test.go | 38 +++++++++ exchange/adapter_builders.go | 4 +- exchange/adapter_util.go | 1 + openrtb_ext/bidders.go | 4 +- openrtb_ext/imp_adoppler.go | 6 -- openrtb_ext/imp_elementaltv.go | 5 ++ static/bidder-info/adoppler.yaml | 12 --- static/bidder-info/elementaltv.yaml | 17 ++++ .../{adoppler.json => elementaltv.json} | 8 +- 23 files changed, 115 insertions(+), 165 deletions(-) delete mode 100644 adapters/adoppler/adoppler_test.go delete mode 100644 adapters/adoppler/adopplertest/exemplary/custom-client.json rename adapters/{adoppler/adoppler.go => elementaltv/elementaltv.go} (87%) create mode 100644 adapters/elementaltv/elementaltv_test.go rename adapters/{adoppler/adopplertest/exemplary/default-client.json => elementaltv/elementaltvtest/exemplary/base.json} (95%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/exemplary/multiimp.json (95%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/bad-request.json (92%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/duplicate-imp.json (94%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/invalid-impid.json (94%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/invalid-response.json (92%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/invalid-video-ext.json (95%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/missing-adunit.json (87%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/no-bid.json (91%) rename adapters/{adoppler/adopplertest => elementaltv/elementaltvtest}/supplemental/server-error.json (92%) create mode 100644 adapters/elementaltv/params_test.go delete mode 100644 openrtb_ext/imp_adoppler.go create mode 100644 openrtb_ext/imp_elementaltv.go delete mode 100644 static/bidder-info/adoppler.yaml create mode 100644 static/bidder-info/elementaltv.yaml rename static/bidder-params/{adoppler.json => elementaltv.json} (66%) diff --git a/adapters/adoppler/adoppler_test.go b/adapters/adoppler/adoppler_test.go deleted file mode 100644 index 3c6888f312..0000000000 --- a/adapters/adoppler/adoppler_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package adoppler - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderAdoppler, config.Adapter{ - Endpoint: "http://{{.AccountID}}.trustedmarketplace.com/processHeaderBid/{{.AdUnit}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) - - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } - - adapterstest.RunJSONBidderTest(t, "adopplertest", bidder) -} diff --git a/adapters/adoppler/adopplertest/exemplary/custom-client.json b/adapters/adoppler/adopplertest/exemplary/custom-client.json deleted file mode 100644 index fe92c36390..0000000000 --- a/adapters/adoppler/adopplertest/exemplary/custom-client.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "mockBidRequest":{ - "id":"req1", - "imp":[ - { - "id":"imp1", - "banner":{ - "w":100, - "h":200 - }, - "ext":{ - "bidder":{ - "adunit":"unit1", - "client":"client1" - } - } - } - ] - }, - "httpCalls":[ - { - "expectedRequest":{ - "uri":"http://client1.trustedmarketplace.com/processHeaderBid/unit1", - "body":{ - "id":"req1-unit1", - "imp":[ - { - "id":"imp1", - "banner":{ - "w":100, - "h":200 - }, - "ext":{ - "bidder":{ - "adunit":"unit1", - "client":"client1" - } - } - } - ] - }, - "impIDs":["imp1"] - }, - "mockResponse":{ - "status":200, - "body":{ - "id":"req1-unit1", - "seatbid":[ - { - "bid":[ - { - "id":"req1-unit1-bid1", - "impid":"imp1", - "price":0.12, - "adm":"<b>An ad</b>" - } - ] - } - ], - "cur":"USD" - } - } - } - ], - "expectedBidResponses":[ - { - "currency":"USD", - "bids":[ - { - "bid":{ - "id":"req1-unit1-bid1", - "impid":"imp1", - "price":0.12, - "adm":"<b>An ad</b>" - }, - "type":"banner" - } - ] - } - ] -} diff --git a/adapters/adoppler/adoppler.go b/adapters/elementaltv/elementaltv.go similarity index 87% rename from adapters/adoppler/adoppler.go rename to adapters/elementaltv/elementaltv.go index ace52b93b1..4495973313 100644 --- a/adapters/adoppler/adoppler.go +++ b/adapters/elementaltv/elementaltv.go @@ -1,8 +1,7 @@ -package adoppler +package elementaltv import ( "encoding/json" - "errors" "fmt" "net/http" "net/url" @@ -17,12 +16,10 @@ import ( "github.com/prebid/prebid-server/v3/util/jsonutil" ) -const DefaultClient = "app" - var bidHeaders http.Header = map[string][]string{ "Accept": {"application/json"}, "Content-Type": {"application/json;charset=utf-8"}, - "X-OpenRTB-Version": {"2.5"}, + "X-OpenRTB-Version": {"2.6"}, } type adsVideoExt struct { @@ -33,24 +30,24 @@ type adsImpExt struct { Video *adsVideoExt `json:"video"` } -type AdopplerAdapter struct { +type adapter struct { endpoint *template.Template } -// Builder builds a new instance of the Adoppler adapter for the given bidder with the given config. +// Builder builds a new instance of the ElementalTV adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + return nil, fmt.Errorf("unable to parse endpoint url template: %w", err) } - bidder := &AdopplerAdapter{ + bidder := &adapter{ endpoint: template, } return bidder, nil } -func (ads *AdopplerAdapter) MakeRequests( +func (ads *adapter) MakeRequests( req *openrtb2.BidRequest, info *adapters.ExtraRequestInfo, ) ( @@ -74,7 +71,7 @@ func (ads *AdopplerAdapter) MakeRequests( r.ID = req.ID + "-" + ext.AdUnit r.Imp = []openrtb2.Imp{imp} - body, err := json.Marshal(r) + body, err := jsonutil.Marshal(r) if err != nil { errs = append(errs, err) continue @@ -100,7 +97,7 @@ func (ads *AdopplerAdapter) MakeRequests( return datas, errs } -func (ads *AdopplerAdapter) MakeBids( +func (ads *adapter) MakeBids( intReq *openrtb2.BidRequest, extReq *adapters.RequestData, resp *adapters.ResponseData, @@ -193,33 +190,29 @@ func (ads *AdopplerAdapter) MakeBids( return adsResp, nil } -func (ads *AdopplerAdapter) bidUri(ext *openrtb_ext.ExtImpAdoppler) (string, error) { +func (ads *adapter) bidUri(ext *openrtb_ext.ExtImpElementalTV) (string, error) { params := macros.EndpointTemplateParams{} params.AdUnit = url.PathEscape(ext.AdUnit) - if ext.Client == "" { - params.AccountID = DefaultClient - } else { - params.AccountID = url.PathEscape(ext.Client) - } - return macros.ResolveMacros(ads.endpoint, params) } -func unmarshalExt(ext json.RawMessage) (*openrtb_ext.ExtImpAdoppler, error) { +func unmarshalExt(ext json.RawMessage) (*openrtb_ext.ExtImpElementalTV, error) { var bext adapters.ExtImpBidder err := jsonutil.Unmarshal(ext, &bext) if err != nil { return nil, err } - var adsExt openrtb_ext.ExtImpAdoppler + var adsExt openrtb_ext.ExtImpElementalTV err = jsonutil.Unmarshal(bext.Bidder, &adsExt) if err != nil { return nil, err } if adsExt.AdUnit == "" { - return nil, errors.New("$.imp.ext.adoppler.adunit required") + return nil, &errortypes.BadInput{ + Message: "$.imp.ext.bidder.adunit required", + } } return &adsExt, nil diff --git a/adapters/elementaltv/elementaltv_test.go b/adapters/elementaltv/elementaltv_test.go new file mode 100644 index 0000000000..7dd0103848 --- /dev/null +++ b/adapters/elementaltv/elementaltv_test.go @@ -0,0 +1,19 @@ +package elementaltv + +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/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderElementalTV, config.Adapter{ + Endpoint: "https://pbs.elementaltv.io/processHeaderBid/{{.AdUnit}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + require.NoError(t, buildErr, "Builder returned unexpected error") + + adapterstest.RunJSONBidderTest(t, "elementaltvtest", bidder) +} diff --git a/adapters/adoppler/adopplertest/exemplary/default-client.json b/adapters/elementaltv/elementaltvtest/exemplary/base.json similarity index 95% rename from adapters/adoppler/adopplertest/exemplary/default-client.json rename to adapters/elementaltv/elementaltvtest/exemplary/base.json index dd53208f7d..b7913c6597 100644 --- a/adapters/adoppler/adopplertest/exemplary/default-client.json +++ b/adapters/elementaltv/elementaltvtest/exemplary/base.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/adoppler/adopplertest/exemplary/multiimp.json b/adapters/elementaltv/elementaltvtest/exemplary/multiimp.json similarity index 95% rename from adapters/adoppler/adopplertest/exemplary/multiimp.json rename to adapters/elementaltv/elementaltvtest/exemplary/multiimp.json index bdbef5a4af..6575a50300 100644 --- a/adapters/adoppler/adopplertest/exemplary/multiimp.json +++ b/adapters/elementaltv/elementaltvtest/exemplary/multiimp.json @@ -44,7 +44,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ @@ -86,7 +86,7 @@ }, { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit2", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit2", "body":{ "id":"req1-unit2", "imp":[ @@ -141,7 +141,7 @@ }, { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit3", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit3", "body":{ "id":"req1-unit3", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/bad-request.json b/adapters/elementaltv/elementaltvtest/supplemental/bad-request.json similarity index 92% rename from adapters/adoppler/adopplertest/supplemental/bad-request.json rename to adapters/elementaltv/elementaltvtest/supplemental/bad-request.json index c2e3846020..3fac885c8a 100644 --- a/adapters/adoppler/adopplertest/supplemental/bad-request.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/bad-request.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/duplicate-imp.json b/adapters/elementaltv/elementaltvtest/supplemental/duplicate-imp.json similarity index 94% rename from adapters/adoppler/adopplertest/supplemental/duplicate-imp.json rename to adapters/elementaltv/elementaltvtest/supplemental/duplicate-imp.json index cc24ae03a2..137997c2ce 100644 --- a/adapters/adoppler/adopplertest/supplemental/duplicate-imp.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/duplicate-imp.json @@ -31,7 +31,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ @@ -73,7 +73,7 @@ }, { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit2", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit2", "body":{ "id":"req1-unit2", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/invalid-impid.json b/adapters/elementaltv/elementaltvtest/supplemental/invalid-impid.json similarity index 94% rename from adapters/adoppler/adopplertest/supplemental/invalid-impid.json rename to adapters/elementaltv/elementaltvtest/supplemental/invalid-impid.json index e94a0e0c40..2ea9ed4c32 100644 --- a/adapters/adoppler/adopplertest/supplemental/invalid-impid.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/invalid-impid.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/invalid-response.json b/adapters/elementaltv/elementaltvtest/supplemental/invalid-response.json similarity index 92% rename from adapters/adoppler/adopplertest/supplemental/invalid-response.json rename to adapters/elementaltv/elementaltvtest/supplemental/invalid-response.json index 84342feaa0..81c9ba5968 100644 --- a/adapters/adoppler/adopplertest/supplemental/invalid-response.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/invalid-response.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/invalid-video-ext.json b/adapters/elementaltv/elementaltvtest/supplemental/invalid-video-ext.json similarity index 95% rename from adapters/adoppler/adopplertest/supplemental/invalid-video-ext.json rename to adapters/elementaltv/elementaltvtest/supplemental/invalid-video-ext.json index 6bab4036c5..8f3386c138 100644 --- a/adapters/adoppler/adopplertest/supplemental/invalid-video-ext.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/invalid-video-ext.json @@ -35,7 +35,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ @@ -86,7 +86,7 @@ }, { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit2", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit2", "body":{ "id":"req1-unit2", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/missing-adunit.json b/adapters/elementaltv/elementaltvtest/supplemental/missing-adunit.json similarity index 87% rename from adapters/adoppler/adopplertest/supplemental/missing-adunit.json rename to adapters/elementaltv/elementaltvtest/supplemental/missing-adunit.json index df9bbe5771..92ff8a25eb 100644 --- a/adapters/adoppler/adopplertest/supplemental/missing-adunit.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/missing-adunit.json @@ -24,7 +24,7 @@ ], "expectedMakeRequestsErrors":[ { - "value":"$.imp.ext.adoppler.adunit required", + "value":"$.imp.ext.bidder.adunit required", "comparison":"literal" } ] diff --git a/adapters/adoppler/adopplertest/supplemental/no-bid.json b/adapters/elementaltv/elementaltvtest/supplemental/no-bid.json similarity index 91% rename from adapters/adoppler/adopplertest/supplemental/no-bid.json rename to adapters/elementaltv/elementaltvtest/supplemental/no-bid.json index 9135b4c5f2..6f8099516b 100644 --- a/adapters/adoppler/adopplertest/supplemental/no-bid.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/no-bid.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/adoppler/adopplertest/supplemental/server-error.json b/adapters/elementaltv/elementaltvtest/supplemental/server-error.json similarity index 92% rename from adapters/adoppler/adopplertest/supplemental/server-error.json rename to adapters/elementaltv/elementaltvtest/supplemental/server-error.json index dcd45e3718..5341d2473a 100644 --- a/adapters/adoppler/adopplertest/supplemental/server-error.json +++ b/adapters/elementaltv/elementaltvtest/supplemental/server-error.json @@ -19,7 +19,7 @@ "httpCalls":[ { "expectedRequest":{ - "uri":"http://app.trustedmarketplace.com/processHeaderBid/unit1", + "uri":"https://pbs.elementaltv.io/processHeaderBid/unit1", "body":{ "id":"req1-unit1", "imp":[ diff --git a/adapters/elementaltv/params_test.go b/adapters/elementaltv/params_test.go new file mode 100644 index 0000000000..9a125d126b --- /dev/null +++ b/adapters/elementaltv/params_test.go @@ -0,0 +1,38 @@ +package elementaltv + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/require" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoErrorf(t, err, "Failed to fetch the json schema: %v", err) + for _, p := range validParams { + err := validator.Validate(openrtb_ext.BidderElementalTV, json.RawMessage(p)) + require.NoError(t, err, "Schema rejected valid params: %s", p) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoErrorf(t, err, "Failed to fetch the json schema: %v", err) + + for _, p := range invalidParams { + err := validator.Validate(openrtb_ext.BidderElementalTV, json.RawMessage(p)) + require.Error(t, err, "Schema allowed invalid params: %s", p) + } +} + +var validParams = []string{ + `{"adunit":"123"}`, + `{"adunit":"SSP:123"}`, + `{"adunit":"5346"}`} + +var invalidParams = []string{ + `{}`, + `{"adunitt":"123"}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 2d55c196b6..b6ca31eb1c 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -17,7 +17,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/admatic" "github.com/prebid/prebid-server/v3/adapters/admixer" "github.com/prebid/prebid-server/v3/adapters/adnuntius" - "github.com/prebid/prebid-server/v3/adapters/adoppler" "github.com/prebid/prebid-server/v3/adapters/adot" "github.com/prebid/prebid-server/v3/adapters/adpone" "github.com/prebid/prebid-server/v3/adapters/adprime" @@ -100,6 +99,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/driftpixel" evolution "github.com/prebid/prebid-server/v3/adapters/e_volution" "github.com/prebid/prebid-server/v3/adapters/edge226" + "github.com/prebid/prebid-server/v3/adapters/elementaltv" "github.com/prebid/prebid-server/v3/adapters/emtv" "github.com/prebid/prebid-server/v3/adapters/eplanning" "github.com/prebid/prebid-server/v3/adapters/epom" @@ -284,7 +284,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdmatic: admatic.Builder, openrtb_ext.BidderAdmixer: admixer.Builder, openrtb_ext.BidderAdnuntius: adnuntius.Builder, - openrtb_ext.BidderAdoppler: adoppler.Builder, openrtb_ext.BidderAdot: adot.Builder, openrtb_ext.BidderAdpone: adpone.Builder, openrtb_ext.BidderAdprime: adprime.Builder, @@ -366,6 +365,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEdge226: edge226.Builder, openrtb_ext.BidderDmx: dmx.Builder, openrtb_ext.BidderDriftPixel: driftpixel.Builder, + openrtb_ext.BidderElementalTV: elementaltv.Builder, openrtb_ext.BidderEmtv: emtv.Builder, openrtb_ext.BidderEmxDigital: cadentaperturemx.Builder, openrtb_ext.BidderEPlanning: eplanning.Builder, diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 879ef75a8b..05487fe278 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -132,6 +132,7 @@ func GetDisabledBidderWarningMessages(infos config.BidderInfos) map[string]strin "dxkulture": `Bidder "dxkulture" is no longer available in Prebid Server. Please update your configuration.`, "mobupps": `Bidder "mobupps" is no longer available in Prebid Server. Please update your configuration.`, "vimayx": `Bidder "vimayx" is no longer available in Prebid Server. Please update your configuration.`, + "adoppler": `Bidder "adoppler" is no longer available in Prebid Server. If you're looking to use the Adoppler adapter, please rename it to "elementaltv" in your configuration.`, } return mergeRemovedAndDisabledBidderWarningMessages(removed, infos) diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 9bb576fd52..1b61ff724e 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -33,7 +33,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdmatic, BidderAdmixer, BidderAdnuntius, - BidderAdoppler, BidderAdot, BidderAdpone, BidderAdprime, @@ -115,6 +114,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderEdge226, BidderDmx, BidderDriftPixel, + BidderElementalTV, BidderEmtv, BidderEmxDigital, BidderEPlanning, @@ -407,7 +407,6 @@ const ( BidderAdmatic BidderName = "admatic" BidderAdmixer BidderName = "admixer" BidderAdnuntius BidderName = "adnuntius" - BidderAdoppler BidderName = "adoppler" BidderAdot BidderName = "adot" BidderAdpone BidderName = "adpone" BidderAdprime BidderName = "adprime" @@ -489,6 +488,7 @@ const ( BidderEdge226 BidderName = "edge226" BidderDmx BidderName = "dmx" BidderDriftPixel BidderName = "driftpixel" + BidderElementalTV BidderName = "elementaltv" BidderEmtv BidderName = "emtv" BidderEmxDigital BidderName = "emx_digital" BidderEPlanning BidderName = "eplanning" diff --git a/openrtb_ext/imp_adoppler.go b/openrtb_ext/imp_adoppler.go deleted file mode 100644 index 9d4d5e5ca0..0000000000 --- a/openrtb_ext/imp_adoppler.go +++ /dev/null @@ -1,6 +0,0 @@ -package openrtb_ext - -type ExtImpAdoppler struct { - Client string `json:"client"` - AdUnit string `json:"adunit"` -} diff --git a/openrtb_ext/imp_elementaltv.go b/openrtb_ext/imp_elementaltv.go new file mode 100644 index 0000000000..a1f267f971 --- /dev/null +++ b/openrtb_ext/imp_elementaltv.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpElementalTV struct { + AdUnit string `json:"adunit"` +} diff --git a/static/bidder-info/adoppler.yaml b/static/bidder-info/adoppler.yaml deleted file mode 100644 index 3db2c1f998..0000000000 --- a/static/bidder-info/adoppler.yaml +++ /dev/null @@ -1,12 +0,0 @@ -endpoint: "http://{{.AccountID}}.trustedmarketplace.io/ads/processHeaderBid/{{.AdUnit}}" -maintainer: - email: pbs@adoppler.com -capabilities: - app: - mediaTypes: - - banner - - video - site: - mediaTypes: - - banner - - video diff --git a/static/bidder-info/elementaltv.yaml b/static/bidder-info/elementaltv.yaml new file mode 100644 index 0000000000..ffc219f7f7 --- /dev/null +++ b/static/bidder-info/elementaltv.yaml @@ -0,0 +1,17 @@ +endpoint: "https://pbs.elementaltv.io/ads/processHeaderBid/{{.AdUnit}}" +endpointCompression: gzip +openrtb: + version: 2.6 +maintainer: + email: support@elementaltv.com +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/adoppler.json b/static/bidder-params/elementaltv.json similarity index 66% rename from static/bidder-params/adoppler.json rename to static/bidder-params/elementaltv.json index 508eef478c..fbe36a9606 100644 --- a/static/bidder-params/adoppler.json +++ b/static/bidder-params/elementaltv.json @@ -1,16 +1,12 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Adoppler Adapter Params", - "description": "A schema which validates params accepted by the Adoppler adapter", + "title": "ElementalTV Adapter Params", + "description": "A schema which validates params accepted by the ElementalTV adapter", "type": "object", "properties": { "adunit": { "type": "string", "description": "AdUnit to bid against to." - }, - "client": { - "type": "string", - "description": "Client name." } }, "required": ["adunit"] From b4b730e5e60ad519a1067225d99d8feb59e99814 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 4 Mar 2026 16:42:34 -0500 Subject: [PATCH 182/272] GVL: Periodically fetch latest valid IDs indicating deletions (#4700) --- config/config.go | 2 + config/config_test.go | 3 + gdpr/gdpr.go | 7 +- gdpr/gdpr_test.go | 2 +- gdpr/gvl_vendor_ids.go | 119 ++++++++++++++++++ gdpr/gvl_vendor_ids_test.go | 169 ++++++++++++++++++++++++++ gdpr/impl.go | 22 +++- gdpr/impl_test.go | 88 ++++++++++++++ gdpr/vendorlist-fetching.go | 6 +- metrics/config/metrics.go | 9 ++ metrics/go_metrics.go | 14 +++ metrics/go_metrics_test.go | 2 + metrics/metrics.go | 1 + metrics/metrics_mock.go | 4 + metrics/prometheus/prometheus.go | 18 +++ metrics/prometheus/prometheus_test.go | 20 +++ router/router.go | 12 +- 17 files changed, 487 insertions(+), 11 deletions(-) create mode 100644 gdpr/gvl_vendor_ids.go create mode 100644 gdpr/gvl_vendor_ids_test.go diff --git a/config/config.go b/config/config.go index e7c4951f7b..3bafb3b240 100644 --- a/config/config.go +++ b/config/config.go @@ -273,6 +273,7 @@ type GDPR struct { NonStandardPublisherMap map[string]struct{} TCF2 TCF2 `mapstructure:"tcf2"` AMPException bool `mapstructure:"amp_exception"` // Deprecated: Use account-level GDPR settings (gdpr.integration_enabled.amp) instead + LiveGVLRefreshInterval int `mapstructure:"live_gvl_refresh_interval_seconds"` // EEACountries (EEA = European Economic Area) are a list of countries where we should assume GDPR applies. // If the gdpr flag is unset in a request, but geo.country is set, we will assume GDPR applies if and only // if the country matches one on this list. If both the GDPR flag and country are not set, we default @@ -1176,6 +1177,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0) v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0) v.SetDefault("gdpr.non_standard_publishers", []string{""}) + v.SetDefault("gdpr.live_gvl_refresh_interval_seconds", 86400) // 1 day v.SetDefault("gdpr.tcf2.enabled", true) v.SetDefault("gdpr.tcf2.purpose1.enforce_vendors", true) v.SetDefault("gdpr.tcf2.purpose2.enforce_vendors", true) diff --git a/config/config_test.go b/config/config_test.go index ed66234c8c..c2dd90f743 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -255,6 +255,7 @@ func TestDefaults(t *testing.T) { cmpInts(t, "analytics.agma.buffers.count", 100, cfg.Analytics.Agma.Buffers.EventCount) cmpStrings(t, "analytics.agma.buffers.timeout", "15m", cfg.Analytics.Agma.Buffers.Timeout) cmpInts(t, "analytics.agma.accounts", 0, len(cfg.Analytics.Agma.Accounts)) + cmpInts(t, "gdpr.live_gvl_refresh_interval_seconds", 86400, cfg.GDPR.LiveGVLRefreshInterval) expectedTCF2 := TCF2{ Enabled: true, Purpose1: TCF2Purpose{ @@ -387,6 +388,7 @@ gdpr: default_value: "1" non_standard_publishers: ["pub1", "pub2"] eea_countries: ["eea1", "eea2"] + live_gvl_refresh_interval_seconds: 3600 tcf2: purpose1: enforce_vendors: false @@ -688,6 +690,7 @@ func TestFullConfig(t *testing.T) { cmpInts(t, "http_client_cache.idle_connection_timeout_seconds", 3, cfg.CacheClient.IdleConnTimeout) cmpInts(t, "gdpr.host_vendor_id", 15, cfg.GDPR.HostVendorID) cmpStrings(t, "gdpr.default_value", "1", cfg.GDPR.DefaultValue) + cmpInts(t, "gdpr.live_gvl_refresh_interval_seconds", 3600, cfg.GDPR.LiveGVLRefreshInterval) cmpBools(t, "video.enable_deprecated_endpoint", true, cfg.Video.EnableDeprecatedEndpoint) cmpStrings(t, "host_schain_node.asi", "pbshostcompany.com", cfg.HostSChainNode.ASI) cmpStrings(t, "host_schain_node.sid", "00001", cfg.HostSChainNode.SID) diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go index 26e04e0b95..d8cd56fe41 100644 --- a/gdpr/gdpr.go +++ b/gdpr/gdpr.go @@ -35,16 +35,16 @@ type RequestInfo struct { } // NewPermissionsBuilder takes host config data used to configure the builder function it returns -func NewPermissionsBuilder(cfg config.GDPR, gvlVendorIDs map[openrtb_ext.BidderName]uint16, vendorListFetcher VendorListFetcher, me metrics.MetricsEngine) PermissionsBuilder { +func NewPermissionsBuilder(cfg config.GDPR, gvlVendorIDs map[openrtb_ext.BidderName]uint16, validGVLVendorIDs *LiveGVLVendorIDs, vendorListFetcher VendorListFetcher, me metrics.MetricsEngine) PermissionsBuilder { return func(tcf2Cfg TCF2ConfigReader, requestInfo RequestInfo) Permissions { purposeEnforcerBuilder := NewPurposeEnforcerBuilder(tcf2Cfg) - return NewPermissions(cfg, tcf2Cfg, gvlVendorIDs, vendorListFetcher, purposeEnforcerBuilder, requestInfo, me) + return NewPermissions(cfg, tcf2Cfg, gvlVendorIDs, validGVLVendorIDs, vendorListFetcher, purposeEnforcerBuilder, requestInfo, me) } } // NewPermissions gets a per-request Permissions object that can then be used to check GDPR permissions for a given bidder. -func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[openrtb_ext.BidderName]uint16, fetcher VendorListFetcher, purposeEnforcerBuilder PurposeEnforcerBuilder, requestInfo RequestInfo, metricsEngine metrics.MetricsEngine) Permissions { +func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[openrtb_ext.BidderName]uint16, validGVLVendorIDs *LiveGVLVendorIDs, fetcher VendorListFetcher, purposeEnforcerBuilder PurposeEnforcerBuilder, requestInfo RequestInfo, metricsEngine metrics.MetricsEngine) Permissions { if !cfg.Enabled { return &AlwaysAllow{} } @@ -55,6 +55,7 @@ func NewPermissions(cfg config.GDPR, tcf2Config TCF2ConfigReader, vendorIDs map[ hostVendorID: cfg.HostVendorID, nonStandardPublishers: cfg.NonStandardPublisherMap, cfg: tcf2Config, + validGVLVendorIDs: validGVLVendorIDs, vendorIDs: vendorIDs, publisherID: requestInfo.PublisherID, gdprSignal: SignalNormalize(requestInfo.GDPRSignal, cfg.DefaultValue), diff --git a/gdpr/gdpr_test.go b/gdpr/gdpr_test.go index 6329dad858..01e829ebfc 100644 --- a/gdpr/gdpr_test.go +++ b/gdpr/gdpr_test.go @@ -51,7 +51,7 @@ func TestNewPermissions(t *testing.T) { fakePurposeEnforcerBuilder := fakePurposeEnforcerBuilder{ purposeEnforcer: nil, }.Builder - perms := NewPermissions(config, &tcf2Config{}, vendorIDs, vendorListFetcher, fakePurposeEnforcerBuilder, RequestInfo{}, &metrics.MetricsEngineMock{}) + perms := NewPermissions(config, &tcf2Config{}, vendorIDs, nil, vendorListFetcher, fakePurposeEnforcerBuilder, RequestInfo{}, &metrics.MetricsEngineMock{}) assert.IsType(t, tt.wantType, perms, tt.description) } diff --git a/gdpr/gvl_vendor_ids.go b/gdpr/gvl_vendor_ids.go new file mode 100644 index 0000000000..401642c56a --- /dev/null +++ b/gdpr/gvl_vendor_ids.go @@ -0,0 +1,119 @@ +package gdpr + +import ( + "context" + "encoding/json" + "io" + "net/http" + "sync/atomic" + "time" + + "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v3/util/task" + "golang.org/x/net/context/ctxhttp" +) + +// LiveGVLVendorIDs provides thread-safe access to the set of vendor IDs present in the latest +// Global Vendor List. It uses atomic.Value so reads (on every request) are lock-free, while +// writes (periodic refresh) are safe without mutexes. +type LiveGVLVendorIDs struct { + ids atomic.Value // holds map[uint16]struct{} +} + +// NewLiveGVLVendorIDs creates a LiveGVLVendorIDs initialized with an empty set. +func NewLiveGVLVendorIDs() *LiveGVLVendorIDs { + l := &LiveGVLVendorIDs{} + l.ids.Store(make(map[uint16]struct{})) + return l +} + +// Contains returns true if the given vendor ID is in the current valid set. +// If the set is empty (e.g. the GVL fetch failed), all IDs are considered valid +// as a safe fallback. +func (l *LiveGVLVendorIDs) Contains(id uint16) bool { + m := l.ids.Load().(map[uint16]struct{}) + if len(m) == 0 { + return true + } + _, ok := m[id] + return ok +} + +// Update atomically replaces the valid vendor ID set. If newIDs is empty, the existing +// set is retained. +func (l *LiveGVLVendorIDs) Update(newIDs map[uint16]struct{}) { + if len(newIDs) > 0 { + l.ids.Store(newIDs) + } +} + +// NewGVLVendorIDTickerTask creates a TickerTask that fetches the latest GVL vendor IDs and +// updates the LiveGVLVendorIDs set. Calling Start on the returned task performs the initial +// fetch immediately and then schedules periodic refreshes at the given interval. +func NewGVLVendorIDTickerTask(interval time.Duration, client *http.Client, urlMaker func(uint16, uint16) string, live *LiveGVLVendorIDs, me metrics.MetricsEngine) *task.TickerTask { + return task.NewTickerTaskFromFunc(interval, func() error { + newIDs := FetchLatestGVLVendorIDs(context.Background(), client, urlMaker, me) + live.Update(newIDs) + return nil + }) +} + +// gvlVendorListContract is a lightweight contract for parsing only vendor IDs from GVL JSON +type gvlVendorListContract struct { + Vendors map[string]struct { + ID uint16 `json:"id"` + } `json:"vendors"` +} + +// FetchLatestGVLVendorIDs fetches the most recent Global Vendor List and returns a set of all +// vendor IDs present in it. The returned map has vendor IDs as keys and empty structs as values. +// If the fetch or parse fails, an empty map is returned. +func FetchLatestGVLVendorIDs(ctx context.Context, client *http.Client, urlMaker func(uint16, uint16) string, me metrics.MetricsEngine) map[uint16]struct{} { + vendorIDs := make(map[uint16]struct{}) + + // Fetch latest GVL for the latest spec version (listVersion 0 means latest) + url := urlMaker(latestSpecVersion, 0) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + logger.Errorf("Failed to build GET %s request for GVL vendor ID extraction: %v", url, err) + me.RecordLiveGVLFetch(false) + return vendorIDs + } + + resp, err := ctxhttp.Do(ctx, client, req) + if err != nil { + logger.Errorf("Error calling GET %s for GVL vendor ID extraction: %v", url, err) + me.RecordLiveGVLFetch(false) + return vendorIDs + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + logger.Errorf("GET %s returned %d for GVL vendor ID extraction", url, resp.StatusCode) + me.RecordLiveGVLFetch(false) + return vendorIDs + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + logger.Errorf("Error reading response body from GET %s for GVL vendor ID extraction: %v", url, err) + me.RecordLiveGVLFetch(false) + return vendorIDs + } + + var contract gvlVendorListContract + if err := json.Unmarshal(respBody, &contract); err != nil { + logger.Errorf("GET %s returned malformed JSON for GVL vendor ID extraction: %v", url, err) + me.RecordLiveGVLFetch(false) + return vendorIDs + } + + for _, v := range contract.Vendors { + vendorIDs[v.ID] = struct{}{} + } + + me.RecordLiveGVLFetch(true) + return vendorIDs +} diff --git a/gdpr/gvl_vendor_ids_test.go b/gdpr/gvl_vendor_ids_test.go new file mode 100644 index 0000000000..d9974176b8 --- /dev/null +++ b/gdpr/gvl_vendor_ids_test.go @@ -0,0 +1,169 @@ +package gdpr + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/prebid/prebid-server/v3/metrics" + "github.com/stretchr/testify/assert" +) + +func TestFetchLatestGVLVendorIDs(t *testing.T) { + tests := []struct { + name string + settings serverSettings + expectedIDs map[uint16]struct{} + expectError bool + }{ + { + name: "fetch-with-multiple-vendors", + settings: serverSettings{ + vendorListLatestVersion: 1, + vendorLists: map[int]map[int]string{ + 3: { + 1: MarshalVendorList(vendorList{ + GVLSpecificationVersion: 3, + VendorListVersion: 1, + Vendors: map[string]*vendor{ + "10": {ID: 10}, + "20": {ID: 20}, + "100": {ID: 100}, + }, + }), + }, + }, + }, + expectedIDs: map[uint16]struct{}{ + 10: {}, + 20: {}, + 100: {}, + }, + }, + { + name: "fetch-with-no-vendors", + settings: serverSettings{ + vendorListLatestVersion: 1, + vendorLists: map[int]map[int]string{ + 3: { + 1: MarshalVendorList(vendorList{ + GVLSpecificationVersion: 3, + VendorListVersion: 1, + Vendors: map[string]*vendor{}, + }), + }, + }, + }, + expectedIDs: map[uint16]struct{}{}, + }, + { + name: "error-spec-v3-not-available", + settings: serverSettings{ + vendorListLatestVersion: 1, + vendorLists: map[int]map[int]string{ + 2: { + 1: MarshalVendorList(vendorList{ + GVLSpecificationVersion: 2, + VendorListVersion: 1, + Vendors: map[string]*vendor{"5": {ID: 5}}, + }), + }, + }, + }, + expectedIDs: map[uint16]struct{}{}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(mockServer(tt.settings))) + defer server.Close() + + m := &metrics.MetricsEngineMock{} + if tt.expectError { + m.On("RecordLiveGVLFetch", false).Once() + } else { + m.On("RecordLiveGVLFetch", true).Once() + } + result := FetchLatestGVLVendorIDs(context.Background(), server.Client(), testURLMaker(server), m) + assert.Equal(t, tt.expectedIDs, result) + m.AssertExpectations(t) + }) + } +} + +func TestFetchLatestGVLVendorIDsServerError(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer server.Close() + + m := &metrics.MetricsEngineMock{} + m.On("RecordLiveGVLFetch", false).Once() + result := FetchLatestGVLVendorIDs(context.Background(), server.Client(), testURLMaker(server), m) + assert.Empty(t, result) + m.AssertExpectations(t) +} + +func TestFetchLatestGVLVendorIDsMalformedJSON(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte("not valid json")) + })) + defer server.Close() + + m := &metrics.MetricsEngineMock{} + m.On("RecordLiveGVLFetch", false).Once() + result := FetchLatestGVLVendorIDs(context.Background(), server.Client(), testURLMaker(server), m) + assert.Empty(t, result) + m.AssertExpectations(t) +} + +func TestLiveGVLVendorIDsContains(t *testing.T) { + tests := []struct { + name string + ids map[uint16]struct{} + checkID uint16 + expected bool + }{ + { + name: "empty-set-returns-true-for-any-id", + ids: map[uint16]struct{}{}, + checkID: 42, + expected: true, + }, + { + name: "id-present-in-set", + ids: map[uint16]struct{}{10: {}, 20: {}}, + checkID: 10, + expected: true, + }, + { + name: "id-not-present-in-set", + ids: map[uint16]struct{}{10: {}, 20: {}}, + checkID: 30, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + live := NewLiveGVLVendorIDs() + live.Update(tt.ids) + assert.Equal(t, tt.expected, live.Contains(tt.checkID)) + }) + } +} + +func TestLiveGVLVendorIDsUpdateSkipsEmpty(t *testing.T) { + live := NewLiveGVLVendorIDs() + live.Update(map[uint16]struct{}{10: {}, 20: {}}) + + // Updating with empty should retain previous set + live.Update(map[uint16]struct{}{}) + assert.True(t, live.Contains(10)) + assert.True(t, live.Contains(20)) + assert.False(t, live.Contains(30)) +} diff --git a/gdpr/impl.go b/gdpr/impl.go index 24c5b3010e..386ce3517b 100644 --- a/gdpr/impl.go +++ b/gdpr/impl.go @@ -23,6 +23,7 @@ type permissionsImpl struct { metrics metrics.MetricsEngine nonStandardPublishers map[string]struct{} purposeEnforcerBuilder PurposeEnforcerBuilder + validGVLVendorIDs *LiveGVLVendorIDs vendorIDs map[openrtb_ext.BidderName]uint16 // request-specific aliasGVLIDs map[string]uint16 @@ -48,7 +49,7 @@ func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_ } id, ok := p.vendorIDs[bidder] - if ok { + if ok && p.isValidVendorID(id) { vendorExceptions := p.cfg.PurposeVendorExceptions(consentconstants.Purpose(1)) _, vendorException := vendorExceptions[string(bidder)] return p.allowSync(ctx, id, bidder, vendorException) @@ -107,17 +108,34 @@ func (p *permissionsImpl) defaultPermissions() AuctionPermissions { } // resolveVendorID gets the vendor ID for the specified bidder from either the alias GVL IDs -// provided in the request or from the bidder configs loaded at startup +// provided in the request or from the bidder configs loaded at startup. If the resolved ID +// is not present in the latest Global Vendor List, it returns 0 and false. func (p *permissionsImpl) resolveVendorID(bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (id uint16, ok bool) { if id, ok = p.aliasGVLIDs[string(bidder)]; ok { + if !p.isValidVendorID(id) { + return 0, false + } return id, ok } id, ok = p.vendorIDs[bidderCoreName] + if ok && !p.isValidVendorID(id) { + return 0, false + } return id, ok } +// isValidVendorID checks whether the given vendor ID exists in the latest Global Vendor List. +// If the valid set is nil (e.g. the GVL fetch failed), all IDs are considered valid +// as a safe fallback. +func (p *permissionsImpl) isValidVendorID(id uint16) bool { + if p.validGVLVendorIDs == nil { + return true + } + return p.validGVLVendorIDs.Contains(id) +} + // allowSync computes cookie sync activity legal basis for a given bidder using the enforcement // algorithms selected by the purpose enforcer builder func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, bidder openrtb_ext.BidderName, vendorException bool) (bool, error) { diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go index 60a688fcc4..ac993f25c1 100644 --- a/gdpr/impl_test.go +++ b/gdpr/impl_test.go @@ -1321,6 +1321,94 @@ func TestDefaultPermissions(t *testing.T) { } } +func TestIsValidVendorID(t *testing.T) { + vendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABCAAIAAAAAAAAAAACEAAAAA" + vendor2AndPurpose2Consent := "CPGWbY_PGWbY_GYAAAENABCAAEAAAAAAAAAAACEAAAAA" + vendorListData := MarshalVendorList(vendorList{ + VendorListVersion: 2, + Vendors: map[string]*vendor{ + "2": { + ID: 2, + Purposes: []int{1, 2}, + }, + }, + }) + + tcf2AggConfig := allPurposesEnabledTCF2Config() + + tests := []struct { + name string + validGVLVendorIDs *LiveGVLVendorIDs + consent string + expectedAllowSync bool + expectedAllowBidReq bool + expectedPassID bool + }{ + { + name: "nil-live-gvl-vendor-ids", + validGVLVendorIDs: nil, + consent: vendor2AndPurpose1Consent, + expectedAllowSync: true, + expectedAllowBidReq: false, + expectedPassID: false, + }, + { + name: "vendor-id-in-live-gvl", + validGVLVendorIDs: func() *LiveGVLVendorIDs { + l := NewLiveGVLVendorIDs() + l.Update(map[uint16]struct{}{2: {}}) + return l + }(), + consent: vendor2AndPurpose2Consent, + expectedAllowSync: false, + expectedAllowBidReq: true, + expectedPassID: true, + }, + { + name: "vendor-id-not-in-live-gvl", + validGVLVendorIDs: func() *LiveGVLVendorIDs { + l := NewLiveGVLVendorIDs() + l.Update(map[uint16]struct{}{99: {}}) + return l + }(), + consent: vendor2AndPurpose2Consent, + expectedAllowSync: false, + expectedAllowBidReq: false, + expectedPassID: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + perms := permissionsImpl{ + cfg: &tcf2AggConfig, + hostVendorID: 2, + vendorIDs: map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + }, + fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ + 2: { + 1: parseVendorListDataV2(t, vendorListData), + }, + }), + purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), + nonStandardPublishers: map[string]struct{}{}, + gdprSignal: SignalYes, + consent: tt.consent, + validGVLVendorIDs: tt.validGVLVendorIDs, + } + + allowSync, err := perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderAppnexus) + assert.NoError(t, err) + assert.Equal(t, tt.expectedAllowSync, allowSync, "BidderSyncAllowed") + + auctionPerms := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus) + assert.Equal(t, tt.expectedAllowBidReq, auctionPerms.AllowBidRequest, "AllowBidRequest") + assert.Equal(t, tt.expectedPassID, auctionPerms.PassID, "PassID") + }) + } +} + func TestVendorListSelection(t *testing.T) { policyVersion3WithVendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABDAAIAAAAAAAAAAACEAAAAA" policyVersion4WithVendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABEAAIAAAAAAAAAAACEAAAAA" diff --git a/gdpr/vendorlist-fetching.go b/gdpr/vendorlist-fetching.go index 2a3be433ec..c97c2bdb75 100644 --- a/gdpr/vendorlist-fetching.go +++ b/gdpr/vendorlist-fetching.go @@ -22,6 +22,10 @@ import ( type saveVendors func(uint16, uint16, api.VendorList) type VendorListFetcher func(ctx context.Context, specVersion uint16, listVersion uint16, metricsEngine metrics.MetricsEngine) (vendorlist.VendorList, error) +// latestSpecVersion is the highest GVL specification version supported. Update this value when +// a new spec version is introduced by the IAB. +const latestSpecVersion = 3 + // This file provides the vendorlist-fetching function for Prebid Server. // // For more info, see https://github.com/prebid/prebid-server/issues/504 @@ -72,7 +76,7 @@ func preloadCache(ctx context.Context, client *http.Client, urlMaker func(uint16 firstListVersion: 2, // The GVL for TCF2 has no vendors defined in its first version. It's very unlikely to be used, so don't preload it. }, { - specVersion: 3, + specVersion: latestSpecVersion, firstListVersion: 1, }, } diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index cb039155bf..5cbfcd6604 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -299,6 +299,12 @@ func (me *MultiMetricsEngine) RecordGvlListRequest() { } } +func (me *MultiMetricsEngine) RecordLiveGVLFetch(success bool) { + for _, thisME := range *me { + thisME.RecordLiveGVLFetch(success) + } +} + func (me *MultiMetricsEngine) RecordAdsCertReq(success bool) { for _, thisME := range *me { thisME.RecordAdsCertReq(success) @@ -534,6 +540,9 @@ func (me *NilMetricsEngine) RecordStoredResponse(pubId string) { func (me *NilMetricsEngine) RecordGvlListRequest() { } +func (me *NilMetricsEngine) RecordLiveGVLFetch(success bool) { +} + func (me *NilMetricsEngine) RecordAdsCertReq(success bool) { } diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index aa64e41a8d..b79916b46b 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -36,6 +36,8 @@ type Metrics struct { BidderServerResponseTimer metrics.Timer StoredResponsesMeter metrics.Meter GvlListRequestsMeter metrics.Meter + LiveGVLFetchSuccess metrics.Meter + LiveGVLFetchFailure metrics.Meter // Metrics for OpenRTB requests specifically RequestStatuses map[RequestType]map[RequestStatus]metrics.Meter @@ -188,6 +190,8 @@ func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetr SyncerSetsMeter: make(map[string]map[SyncerSetUidStatus]metrics.Meter), StoredResponsesMeter: blankMeter, GvlListRequestsMeter: blankMeter, + LiveGVLFetchSuccess: blankMeter, + LiveGVLFetchFailure: blankMeter, ImpsTypeBanner: blankMeter, ImpsTypeVideo: blankMeter, @@ -314,6 +318,8 @@ func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, d newMetrics.PrebidCacheRequestTimerError = metrics.GetOrRegisterTimer("prebid_cache_request_time.err", registry) newMetrics.StoredResponsesMeter = metrics.GetOrRegisterMeter("stored_responses", registry) newMetrics.GvlListRequestsMeter = metrics.GetOrRegisterMeter("gvl_requests", registry) + newMetrics.LiveGVLFetchSuccess = metrics.GetOrRegisterMeter("live_gvl_fetch.ok", registry) + newMetrics.LiveGVLFetchFailure = metrics.GetOrRegisterMeter("live_gvl_fetch.failed", registry) newMetrics.OverheadTimer = makeOverheadTimerMetrics(registry) newMetrics.BidderServerResponseTimer = metrics.GetOrRegisterTimer("bidder_server_response_time_seconds", registry) @@ -658,6 +664,14 @@ func (me *Metrics) RecordGvlListRequest() { me.GvlListRequestsMeter.Mark(1) } +func (me *Metrics) RecordLiveGVLFetch(success bool) { + if success { + me.LiveGVLFetchSuccess.Mark(1) + } else { + me.LiveGVLFetchFailure.Mark(1) + } +} + func (me *Metrics) RecordImps(labels ImpLabels) { me.ImpMeter.Mark(int64(1)) if labels.BannerImps { diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index 2fcec9cb6d..65d8399c8c 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -37,6 +37,8 @@ func TestNewMetrics(t *testing.T) { ensureContains(t, registry, "setuid_requests.syncer_unknown", m.SetUidStatusMeter[SetUidSyncerUnknown]) ensureContains(t, registry, "stored_responses", m.StoredResponsesMeter) ensureContains(t, registry, "gvl_requests", m.GvlListRequestsMeter) + ensureContains(t, registry, "live_gvl_fetch.ok", m.LiveGVLFetchSuccess) + ensureContains(t, registry, "live_gvl_fetch.failed", m.LiveGVLFetchFailure) ensureContains(t, registry, "prebid_cache_request_time.ok", m.PrebidCacheRequestTimerSuccess) ensureContains(t, registry, "prebid_cache_request_time.err", m.PrebidCacheRequestTimerError) diff --git a/metrics/metrics.go b/metrics/metrics.go index 054bf8940a..105d6e8468 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -497,6 +497,7 @@ type MetricsEngine interface { RecordDebugRequest(debugEnabled bool, pubId string) RecordStoredResponse(pubId string) RecordGvlListRequest() + RecordLiveGVLFetch(success bool) RecordAdsCertReq(success bool) RecordAdsCertSignTime(adsCertSignTime time.Duration) RecordBidValidationCreativeSizeError(adapter openrtb_ext.BidderName, account string) diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index 09fa605166..b3b6532f35 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -179,6 +179,10 @@ func (me *MetricsEngineMock) RecordGvlListRequest() { me.Called() } +func (me *MetricsEngineMock) RecordLiveGVLFetch(success bool) { + me.Called(success) +} + func (me *MetricsEngineMock) RecordAdsCertReq(success bool) { me.Called(success) } diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 873161df38..2278ae8d4b 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -55,6 +55,7 @@ type Metrics struct { privacyTCF *prometheus.CounterVec storedResponses prometheus.Counter gvlListRequests prometheus.Counter + liveGVLFetch *prometheus.CounterVec storedResponsesFetchTimer *prometheus.HistogramVec storedResponsesErrors *prometheus.CounterVec adsCertRequests *prometheus.CounterVec @@ -379,6 +380,11 @@ func NewMetrics(cfg config.PrometheusMetrics, disabledMetrics config.DisabledMet "gvl_requests", "Count number of times GVL list is fetched") + metrics.liveGVLFetch = newCounter(cfg, reg, + "live_gvl_fetch", + "Count of live GVL vendor ID fetches labeled by success or failure.", + []string{successLabel}) + metrics.adapterBids = newCounter(cfg, reg, "adapter_bids", "Count of bids labeled by adapter and markup delivery type (adm or nurl).", @@ -739,6 +745,18 @@ func (m *Metrics) RecordGvlListRequest() { m.gvlListRequests.Inc() } +func (m *Metrics) RecordLiveGVLFetch(success bool) { + if success { + m.liveGVLFetch.With(prometheus.Labels{ + successLabel: requestSuccessful, + }).Inc() + } else { + m.liveGVLFetch.With(prometheus.Labels{ + successLabel: requestFailed, + }).Inc() + } +} + func (m *Metrics) RecordImps(labels metrics.ImpLabels) { m.impressions.With(prometheus.Labels{ isBannerLabel: strconv.FormatBool(labels.BannerImps), diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index d4edca8858..971bc74f6b 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -1953,6 +1953,26 @@ func TestRecordGvlListRequest(t *testing.T) { assertCounterValue(t, "Record instance of fetched GVL list", "success", m.gvlListRequests, 1.00) } +func TestRecordLiveGVLFetch(t *testing.T) { + m := createMetricsForTesting() + + m.RecordLiveGVLFetch(true) + m.RecordLiveGVLFetch(true) + m.RecordLiveGVLFetch(false) + + assertCounterVecValue(t, "", "live_gvl_fetch:ok", m.liveGVLFetch, + float64(2), + prometheus.Labels{ + successLabel: requestSuccessful, + }) + + assertCounterVecValue(t, "", "live_gvl_fetch:fail", m.liveGVLFetch, + float64(1), + prometheus.Labels{ + successLabel: requestFailed, + }) +} + func TestRecordAdsCertReqMetric(t *testing.T) { testCases := []struct { description string diff --git a/router/router.go b/router/router.go index 8dab7ade56..376b6215fe 100644 --- a/router/router.go +++ b/router/router.go @@ -220,9 +220,6 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R analyticsRunner := analyticsBuild.New(&cfg.Analytics) - // register the analytics runner for shutdown - r.shutdowns = append(r.shutdowns, shutdown, analyticsRunner.Shutdown, shutdownModules.Shutdown) - paramsValidator, err := openrtb_ext.NewBidderParamsValidator(schemaDirectory) if err != nil { logger.Fatalf("Failed to create the bidder params validator. %v", err) @@ -235,9 +232,16 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R gvlVendorIDs := cfg.BidderInfos.ToGVLVendorIDMap() vendorListFetcher := gdpr.NewVendorListFetcher(context.Background(), cfg.GDPR, generalHttpClient, r.MetricsEngine, gdpr.VendorListURLMaker) - gdprPermsBuilder := gdpr.NewPermissionsBuilder(cfg.GDPR, gvlVendorIDs, vendorListFetcher, r.MetricsEngine) + liveGVLVendorIDs := gdpr.NewLiveGVLVendorIDs() + refreshInterval := time.Duration(cfg.GDPR.LiveGVLRefreshInterval) * time.Second + gvlVendorIDTask := gdpr.NewGVLVendorIDTickerTask(refreshInterval, generalHttpClient, gdpr.VendorListURLMaker, liveGVLVendorIDs, r.MetricsEngine) + gvlVendorIDTask.Start() + gdprPermsBuilder := gdpr.NewPermissionsBuilder(cfg.GDPR, gvlVendorIDs, liveGVLVendorIDs, vendorListFetcher, r.MetricsEngine) tcf2CfgBuilder := gdpr.NewTCF2Config + // register the analytics runner, modules and live GVL Vendor ID ticker task for shutdown + r.shutdowns = append(r.shutdowns, shutdown, analyticsRunner.Shutdown, shutdownModules.Shutdown, gvlVendorIDTask.Stop) + cacheClient := pbc.NewClient(cacheHttpClient, &cfg.CacheURL, &cfg.ExtCacheURL, r.MetricsEngine) adapters, singleFormatAdapters, adaptersErrs := exchange.BuildAdapters(generalHttpClient, cfg, cfg.BidderInfos, r.MetricsEngine) From 27dd5069902e14c509a831341f5d32e69ec151c9 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:23:04 -0500 Subject: [PATCH 183/272] Cookie Sync: Allow turning off sync for specific adapter (#4707) --- config/bidderinfo.go | 4 ++++ config/bidderinfo_test.go | 24 ++++++++++++++++++++++++ config/config.go | 1 + config/config_test.go | 8 ++++++++ 4 files changed, 37 insertions(+) diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 7ded01422c..89ea697e05 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -800,6 +800,10 @@ func (s *Syncer) Override(original *Syncer) *Syncer { copy.ExternalURL = s.ExternalURL } + if s.Enabled != nil { + copy.Enabled = s.Enabled + } + return © } diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 5e01f1fc6d..110c99babd 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -1466,6 +1466,30 @@ func TestSyncerOverride(t *testing.T) { givenOverride: &Syncer{ExternalURL: "overrideExternalURL"}, expected: &Syncer{Key: "originalKey", ExternalURL: "overrideExternalURL"}, }, + { + description: "Override Enabled - True To False", + givenOriginal: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(true)}, + givenOverride: &Syncer{Enabled: ptrutil.ToPtr(false)}, + expected: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(false)}, + }, + { + description: "Override Enabled - False To True", + givenOriginal: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(false)}, + givenOverride: &Syncer{Enabled: ptrutil.ToPtr(true)}, + expected: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(true)}, + }, + { + description: "Override Enabled - Nil Preserves Original", + givenOriginal: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(true)}, + givenOverride: &Syncer{}, + expected: &Syncer{Key: "originalKey", Enabled: ptrutil.ToPtr(true)}, + }, + { + description: "Override Enabled - Set On Nil Original", + givenOriginal: nil, + givenOverride: &Syncer{Enabled: ptrutil.ToPtr(false)}, + expected: &Syncer{Enabled: ptrutil.ToPtr(false)}, + }, } for _, test := range testCases { diff --git a/config/config.go b/config/config.go index 3bafb3b240..30475b2241 100644 --- a/config/config.go +++ b/config/config.go @@ -1381,6 +1381,7 @@ func setBidderDefaults(v *viper.Viper, bidder string) { v.BindEnv(adapterCfgPrefix + ".openrtb.version") v.BindEnv(adapterCfgPrefix + ".openrtb.gpp-supported") + v.BindEnv(adapterCfgPrefix + ".usersync.enabled") v.BindEnv(adapterCfgPrefix + ".usersync.key") v.BindEnv(adapterCfgPrefix + ".usersync.default") v.BindEnv(adapterCfgPrefix + ".usersync.iframe.url") diff --git a/config/config_test.go b/config/config_test.go index c2dd90f743..7c5391cecc 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1051,11 +1051,18 @@ func TestUserSyncFromEnv(t *testing.T) { defer os.Unsetenv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL") } + if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER2_USERSYNC_ENABLED"); ok { + defer os.Setenv("PBS_ADAPTERS_BIDDER2_USERSYNC_ENABLED", oldval) + } else { + defer os.Unsetenv("PBS_ADAPTERS_BIDDER2_USERSYNC_ENABLED") + } + // set new os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", "http://some.url/sync?redirect={{.RedirectURL}}") os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_USER_MACRO", "[UID]") os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_SUPPORT_CORS", "true") os.Setenv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL", "http://somedifferent.url/sync?redirect={{.RedirectURL}}") + os.Setenv("PBS_ADAPTERS_BIDDER2_USERSYNC_ENABLED", "false") cfg, _ := newDefaultConfig(t) @@ -1065,6 +1072,7 @@ func TestUserSyncFromEnv(t *testing.T) { assert.Equal(t, "http://somedifferent.url/sync?redirect={{.RedirectURL}}", cfg.BidderInfos["bidder2"].Syncer.IFrame.URL) assert.Nil(t, cfg.BidderInfos["bidder2"].Syncer.Redirect) + assert.Equal(t, ptrutil.ToPtr(false), cfg.BidderInfos["bidder2"].Syncer.Enabled) } func TestBidderInfoFromEnv(t *testing.T) { From 5dbaf351a8f50a34c21726ace0f3e131d077d875 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:25:08 -0500 Subject: [PATCH 184/272] Fix: Require explicit GVL vendor ID declaration for aliases (#4683) --- config/bidderinfo.go | 6 +++--- config/bidderinfo_test.go | 3 ++- static/bidder-info/adform.yaml | 1 + static/bidder-info/admaticde.yaml | 3 ++- static/bidder-info/copper6.yaml | 1 + static/bidder-info/epsilon.yaml | 1 + static/bidder-info/equativ.yaml | 1 + static/bidder-info/finative.yaml | 3 ++- static/bidder-info/freewheel-ssp.yaml | 1 + static/bidder-info/indicue.yaml | 1 + static/bidder-info/janet.yaml | 1 + static/bidder-info/magnite.yaml | 3 ++- static/bidder-info/monetixads.yaml | 3 ++- static/bidder-info/netaddiction.yaml | 3 ++- static/bidder-info/pgam.yaml | 1 + static/bidder-info/pixad.yaml | 3 ++- static/bidder-info/showheroes-bs.yaml | 3 ++- static/bidder-info/showheroesBs.yaml | 3 ++- static/bidder-info/streamkey.yaml | 1 + static/bidder-info/tagoras.yaml | 1 + static/bidder-info/ttd.yaml | 1 + static/bidder-info/yahooAdvertising.yaml | 1 + static/bidder-info/yahoossp.yaml | 1 + static/bidder-info/yobee.yaml | 3 ++- 24 files changed, 36 insertions(+), 13 deletions(-) diff --git a/config/bidderinfo.go b/config/bidderinfo.go index 89ea697e05..a9add8d93a 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -368,6 +368,9 @@ func processBidderAliases(aliasNillableFieldsByBidder map[string]aliasNillableFi } parentBidderInfo := bidderInfos[aliasBidderInfo.AliasOf] + // Note: The aliasBidderInfo.GVLVendorID is intentionally never set to the parent's + // GVLVendorID. Each alias must declare its own GVL Vendor ID, as inheriting from the + // parent is not safe for legal reasons. if aliasBidderInfo.AppSecret == "" { aliasBidderInfo.AppSecret = parentBidderInfo.AppSecret } @@ -386,9 +389,6 @@ func processBidderAliases(aliasNillableFieldsByBidder map[string]aliasNillableFi if aliasBidderInfo.ExtraAdapterInfo == "" { aliasBidderInfo.ExtraAdapterInfo = parentBidderInfo.ExtraAdapterInfo } - if aliasBidderInfo.GVLVendorID == 0 { - aliasBidderInfo.GVLVendorID = parentBidderInfo.GVLVendorID - } if aliasBidderInfo.Maintainer == nil { aliasBidderInfo.Maintainer = parentBidderInfo.Maintainer } diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 110c99babd..1263f273be 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -253,7 +253,7 @@ func TestProcessBidderInfo(t *testing.T) { }, }, ExtraAdapterInfo: "extra-info", - GVLVendorID: 42, + GVLVendorID: 0, Maintainer: &MaintainerInfo{ Email: "some-email@domain.com", }, @@ -390,6 +390,7 @@ func TestProcessAliasBidderInfo(t *testing.T) { } bidderB := parentWithSyncerKey bidderB.AliasOf = "bidderA" + bidderB.GVLVendorID = 0 bidderB.Syncer = &Syncer{ Key: bidderB.Syncer.Key, } diff --git a/static/bidder-info/adform.yaml b/static/bidder-info/adform.yaml index 6475bb34ca..b25507131b 100644 --- a/static/bidder-info/adform.yaml +++ b/static/bidder-info/adform.yaml @@ -1,4 +1,5 @@ aliasOf: adf +gvlVendorID: 50 userSync: redirect: url: "https://c1.adform.net/cookie?redirect_url={{.RedirectURL}}" diff --git a/static/bidder-info/admaticde.yaml b/static/bidder-info/admaticde.yaml index 562aa18369..fdd9b6107d 100644 --- a/static/bidder-info/admaticde.yaml +++ b/static/bidder-info/admaticde.yaml @@ -1 +1,2 @@ -aliasOf: "admatic" \ No newline at end of file +aliasOf: "admatic" +gvlVendorID: 1281 \ No newline at end of file diff --git a/static/bidder-info/copper6.yaml b/static/bidder-info/copper6.yaml index b4e259ef08..fe3ea47a29 100644 --- a/static/bidder-info/copper6.yaml +++ b/static/bidder-info/copper6.yaml @@ -2,6 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.app.copper6.com/pbs/ortb" maintainer: email: "info@copper6.com" +gvlVendorID: 1356 userSync: # Copper6 ssp supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/epsilon.yaml b/static/bidder-info/epsilon.yaml index cb8318102e..4da155b06f 100644 --- a/static/bidder-info/epsilon.yaml +++ b/static/bidder-info/epsilon.yaml @@ -1,4 +1,5 @@ aliasOf: conversant +gvlVendorID: 24 userSync: redirect: url: "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&rurl={{.RedirectURL}}" diff --git a/static/bidder-info/equativ.yaml b/static/bidder-info/equativ.yaml index 7c5214fe48..512da14d50 100644 --- a/static/bidder-info/equativ.yaml +++ b/static/bidder-info/equativ.yaml @@ -1 +1,2 @@ aliasOf: "smartadserver" +gvlVendorID: 45 diff --git a/static/bidder-info/finative.yaml b/static/bidder-info/finative.yaml index e1136c3220..9201f4eb3f 100644 --- a/static/bidder-info/finative.yaml +++ b/static/bidder-info/finative.yaml @@ -1,2 +1,3 @@ endpoint: "https://b.finative.cloud/cds/rtb/bid?ssp={{.AccountID}}" -aliasOf: "seedingAlliance" \ No newline at end of file +aliasOf: "seedingAlliance" +gvlVendorID: 371 \ No newline at end of file diff --git a/static/bidder-info/freewheel-ssp.yaml b/static/bidder-info/freewheel-ssp.yaml index 43c1ca166a..4b79dd12ab 100644 --- a/static/bidder-info/freewheel-ssp.yaml +++ b/static/bidder-info/freewheel-ssp.yaml @@ -1,4 +1,5 @@ aliasOf: freewheelssp +gvlVendorID: 285 userSync: iframe: url: "https://ads.stickyadstv.com/pbs-user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" diff --git a/static/bidder-info/indicue.yaml b/static/bidder-info/indicue.yaml index 1353424dfe..0548d0ed59 100644 --- a/static/bidder-info/indicue.yaml +++ b/static/bidder-info/indicue.yaml @@ -2,6 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.console.indicue.com/pbs/ortb" maintainer: email: "ops@indicue.com" +gvlVendorID: 410 userSync: # Indicue ssp supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/janet.yaml b/static/bidder-info/janet.yaml index 97f44a2bd5..4a77ef6f48 100644 --- a/static/bidder-info/janet.yaml +++ b/static/bidder-info/janet.yaml @@ -2,6 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.bidder.jmgads.com/pbs/ortb" maintainer: email: "info@thejmg.com" +gvlVendorID: 410 userSync: # JANet supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/magnite.yaml b/static/bidder-info/magnite.yaml index 109c20d03b..a0840a14a8 100644 --- a/static/bidder-info/magnite.yaml +++ b/static/bidder-info/magnite.yaml @@ -1 +1,2 @@ -aliasOf: "rubicon" \ No newline at end of file +aliasOf: "rubicon" +gvlVendorID: 52 \ No newline at end of file diff --git a/static/bidder-info/monetixads.yaml b/static/bidder-info/monetixads.yaml index 95beda701f..32b0d79280 100644 --- a/static/bidder-info/monetixads.yaml +++ b/static/bidder-info/monetixads.yaml @@ -1,3 +1,4 @@ aliasOf: "admatic" maintainer: - email: "team@monetixads.com" \ No newline at end of file + email: "team@monetixads.com" +gvlVendorID: 1281 \ No newline at end of file diff --git a/static/bidder-info/netaddiction.yaml b/static/bidder-info/netaddiction.yaml index 7f6777b4b3..70a26fca5f 100644 --- a/static/bidder-info/netaddiction.yaml +++ b/static/bidder-info/netaddiction.yaml @@ -1,3 +1,4 @@ aliasOf: "admatic" maintainer: - email: "publishers-support@netaddiction.it" \ No newline at end of file + email: "publishers-support@netaddiction.it" +gvlVendorID: 1281 \ No newline at end of file diff --git a/static/bidder-info/pgam.yaml b/static/bidder-info/pgam.yaml index e0bf4388d4..911fa4ef08 100644 --- a/static/bidder-info/pgam.yaml +++ b/static/bidder-info/pgam.yaml @@ -2,6 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.pgamssp.com/pbs/ortb" maintainer: email: "ppatel@pgammedia.com" +gvlVendorID: 1353 userSync: # PGAM ssp supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/pixad.yaml b/static/bidder-info/pixad.yaml index d08230bfbc..bc9a6fe699 100644 --- a/static/bidder-info/pixad.yaml +++ b/static/bidder-info/pixad.yaml @@ -1,3 +1,4 @@ aliasOf: "admatic" maintainer: - email: "prebid@pixad.com.tr" \ No newline at end of file + email: "prebid@pixad.com.tr" +gvlVendorID: 1281 \ No newline at end of file diff --git a/static/bidder-info/showheroes-bs.yaml b/static/bidder-info/showheroes-bs.yaml index 4b49a60f18..7143e05aed 100644 --- a/static/bidder-info/showheroes-bs.yaml +++ b/static/bidder-info/showheroes-bs.yaml @@ -1 +1,2 @@ -aliasOf: "showheroes" \ No newline at end of file +aliasOf: "showheroes" +gvlVendorID: 111 \ No newline at end of file diff --git a/static/bidder-info/showheroesBs.yaml b/static/bidder-info/showheroesBs.yaml index 4b49a60f18..7143e05aed 100644 --- a/static/bidder-info/showheroesBs.yaml +++ b/static/bidder-info/showheroesBs.yaml @@ -1 +1,2 @@ -aliasOf: "showheroes" \ No newline at end of file +aliasOf: "showheroes" +gvlVendorID: 111 \ No newline at end of file diff --git a/static/bidder-info/streamkey.yaml b/static/bidder-info/streamkey.yaml index 20510ceac6..463abd64be 100644 --- a/static/bidder-info/streamkey.yaml +++ b/static/bidder-info/streamkey.yaml @@ -2,6 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.hb.streamkey.net/pbs/ortb" maintainer: email: "contact@streamkey.tv" +gvlVendorID: 410 capabilities: app: mediaTypes: diff --git a/static/bidder-info/tagoras.yaml b/static/bidder-info/tagoras.yaml index c40aaa2a04..f8f94a456d 100644 --- a/static/bidder-info/tagoras.yaml +++ b/static/bidder-info/tagoras.yaml @@ -2,6 +2,7 @@ aliasOf: "vidazoo" endpoint: "https://exchange.tagoras.io/openrtb/" maintainer: email: "prebid@tagoras.io" +gvlVendorID: 1450 userSync: iframe: url: https://sync.tagoras.io/api/user/html/6819bdc3e6bb44545c55f843?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} diff --git a/static/bidder-info/ttd.yaml b/static/bidder-info/ttd.yaml index db055e1a75..78ed8c79b5 100644 --- a/static/bidder-info/ttd.yaml +++ b/static/bidder-info/ttd.yaml @@ -1 +1,2 @@ aliasOf: thetradedesk +gvlVendorID: 21 diff --git a/static/bidder-info/yahooAdvertising.yaml b/static/bidder-info/yahooAdvertising.yaml index f9f34fbfbd..68037fb68f 100644 --- a/static/bidder-info/yahooAdvertising.yaml +++ b/static/bidder-info/yahooAdvertising.yaml @@ -1,4 +1,5 @@ aliasOf: yahooAds +gvlVendorID: 25 userSync: # yahooAdvertising supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/yahoossp.yaml b/static/bidder-info/yahoossp.yaml index 81695624df..132bef5a83 100644 --- a/static/bidder-info/yahoossp.yaml +++ b/static/bidder-info/yahoossp.yaml @@ -1,6 +1,7 @@ aliasOf: yahooAds maintainer: email: "hb-fe-tech@oath.com" +gvlVendorID: 25 userSync: # yahoossp supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. diff --git a/static/bidder-info/yobee.yaml b/static/bidder-info/yobee.yaml index 28ce00e79d..94023eef0b 100644 --- a/static/bidder-info/yobee.yaml +++ b/static/bidder-info/yobee.yaml @@ -1,3 +1,4 @@ aliasOf: "admatic" maintainer: - email: "adops@yobee.it" \ No newline at end of file + email: "adops@yobee.it" +gvlVendorID: 1281 \ No newline at end of file From 615e5dfa5fd9a9925a607e1f0e80591f21d41778 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:38:57 -0500 Subject: [PATCH 185/272] Increment package version to v4 (#4710) --- Dockerfile | 2 +- Makefile | 2 +- account/account.go | 14 +- account/account_test.go | 14 +- adapters/33across/33across.go | 10 +- adapters/33across/33across_test.go | 6 +- adapters/33across/params_test.go | 2 +- adapters/aax/aax.go | 10 +- adapters/aax/aax_test.go | 6 +- adapters/aax/params_test.go | 2 +- adapters/aceex/aceex.go | 12 +- adapters/aceex/aceex_test.go | 6 +- adapters/aceex/params_test.go | 2 +- adapters/acuityads/acuityads.go | 12 +- adapters/acuityads/acuityads_test.go | 6 +- adapters/acuityads/params_test.go | 2 +- adapters/adagio/adagio.go | 10 +- adapters/adagio/adagio_test.go | 6 +- adapters/adagio/params_test.go | 2 +- adapters/adapterstest/test_json.go | 6 +- adapters/adelement/adelement.go | 12 +- adapters/adelement/adelement_test.go | 6 +- adapters/adf/adf.go | 10 +- adapters/adf/adf_test.go | 6 +- adapters/adf/params_test.go | 2 +- adapters/adgeneration/adgeneration.go | 10 +- adapters/adgeneration/adgeneration_test.go | 8 +- adapters/adgeneration/params_test.go | 2 +- adapters/adhese/adhese.go | 12 +- adapters/adhese/adhese_test.go | 6 +- adapters/adhese/params_test.go | 2 +- adapters/adkernel/adkernel.go | 12 +- adapters/adkernel/adkernel_test.go | 6 +- adapters/adkernelAdn/adkernelAdn.go | 12 +- adapters/adkernelAdn/adkernelAdn_test.go | 6 +- adapters/adman/adman.go | 10 +- adapters/adman/adman_test.go | 6 +- adapters/adman/params_test.go | 2 +- adapters/admatic/admatic.go | 12 +- adapters/admatic/admatic_test.go | 6 +- adapters/admatic/params_test.go | 2 +- adapters/admixer/admixer.go | 10 +- adapters/admixer/admixer_test.go | 6 +- adapters/admixer/params_test.go | 2 +- adapters/adnuntius/adnuntius.go | 12 +- adapters/adnuntius/adnuntius_test.go | 8 +- adapters/adnuntius/adnuntius_types.go | 2 +- adapters/adnuntius/adnuntius_utils.go | 4 +- adapters/adnuntius/params_test.go | 2 +- adapters/adot/adot.go | 10 +- adapters/adot/adot_test.go | 8 +- adapters/adot/params_test.go | 2 +- adapters/adpone/adpone.go | 10 +- adapters/adpone/adpone_test.go | 6 +- adapters/adprime/adprime.go | 10 +- adapters/adprime/adprime_test.go | 6 +- adapters/adprime/params_test.go | 2 +- adapters/adquery/adquery.go | 10 +- adapters/adquery/adquery_test.go | 6 +- adapters/adquery/params_test.go | 2 +- adapters/adquery/types.go | 2 +- adapters/adrino/adrino.go | 10 +- adapters/adrino/adrino_test.go | 6 +- adapters/adrino/params_test.go | 2 +- adapters/adtarget/adtarget.go | 10 +- adapters/adtarget/adtarget_test.go | 6 +- adapters/adtarget/params_test.go | 2 +- adapters/adtelligent/adtelligent.go | 10 +- adapters/adtelligent/adtelligent_test.go | 6 +- adapters/adtelligent/params_test.go | 2 +- adapters/adtonos/adtonos.go | 12 +- adapters/adtonos/adtonos_test.go | 6 +- adapters/adtonos/params_test.go | 2 +- adapters/adtrgtme/adtrgtme.go | 10 +- adapters/adtrgtme/adtrgtme_test.go | 6 +- adapters/adtrgtme/params_test.go | 2 +- adapters/aduptech/aduptech.go | 12 +- adapters/aduptech/aduptech_test.go | 6 +- adapters/aduptech/params_test.go | 2 +- adapters/advangelists/advangelists.go | 12 +- adapters/advangelists/advangelists_test.go | 6 +- adapters/advangelists/params_test.go | 2 +- adapters/adverxo/adverxo.go | 10 +- adapters/adverxo/adverxo_test.go | 6 +- adapters/adverxo/params_test.go | 2 +- adapters/adview/adview.go | 12 +- adapters/adview/adview_test.go | 6 +- adapters/adview/params_test.go | 2 +- adapters/adxcg/adxcg.go | 10 +- adapters/adxcg/adxcg_test.go | 6 +- adapters/adyoulike/adyoulike.go | 10 +- adapters/adyoulike/adyoulike_test.go | 6 +- adapters/adyoulike/params_test.go | 2 +- adapters/afront/afront.go | 12 +- adapters/afront/afront_test.go | 6 +- adapters/afront/params_test.go | 2 +- adapters/aidem/aidem.go | 12 +- adapters/aidem/aidem_test.go | 6 +- adapters/aidem/params_test.go | 2 +- adapters/aja/aja.go | 10 +- adapters/aja/aja_test.go | 6 +- adapters/akcelo/akcelo.go | 12 +- adapters/akcelo/akcelo_test.go | 6 +- adapters/akcelo/params_test.go | 2 +- adapters/algorix/algorix.go | 12 +- adapters/algorix/algorix_test.go | 6 +- adapters/algorix/params_test.go | 2 +- adapters/alkimi/alkimi.go | 12 +- adapters/alkimi/alkimi_test.go | 8 +- adapters/alkimi/params_test.go | 2 +- adapters/alliance_gravity/alliance_gravity.go | 10 +- .../alliance_gravity/alliance_gravity_test.go | 6 +- adapters/alliance_gravity/params_test.go | 2 +- adapters/amx/amx.go | 10 +- adapters/amx/amx_test.go | 8 +- adapters/amx/params_test.go | 2 +- adapters/apacdex/apacdex.go | 10 +- adapters/apacdex/apacdex_test.go | 6 +- adapters/apacdex/params_test.go | 2 +- adapters/appnexus/appnexus.go | 18 +- adapters/appnexus/appnexus_test.go | 6 +- adapters/appnexus/params_test.go | 2 +- adapters/appush/appush.go | 10 +- adapters/appush/appush_test.go | 6 +- adapters/appush/params_test.go | 2 +- adapters/aso/aso.go | 12 +- adapters/aso/aso_test.go | 6 +- adapters/aso/params_test.go | 2 +- adapters/audienceNetwork/facebook.go | 14 +- adapters/audienceNetwork/facebook_test.go | 8 +- adapters/automatad/automatad.go | 10 +- adapters/automatad/automatad_test.go | 6 +- adapters/automatad/params_test.go | 2 +- adapters/avocet/avocet.go | 10 +- adapters/avocet/avocet_test.go | 10 +- adapters/axis/axis.go | 10 +- adapters/axis/axis_test.go | 6 +- adapters/axis/params_test.go | 2 +- adapters/axonix/axonix.go | 12 +- adapters/axonix/axonix_test.go | 6 +- adapters/axonix/params_test.go | 2 +- adapters/beachfront/beachfront.go | 12 +- adapters/beachfront/beachfront_test.go | 6 +- adapters/beachfront/params_test.go | 2 +- adapters/beintoo/beintoo.go | 10 +- adapters/beintoo/beintoo_test.go | 6 +- adapters/beintoo/params_test.go | 2 +- adapters/bematterfull/bematterfull.go | 12 +- .../bematterfull/bematterfulltest_test.go | 6 +- adapters/bematterfull/params_test.go | 2 +- adapters/beop/beop.go | 10 +- adapters/beop/beop_test.go | 6 +- adapters/beop/params_test.go | 2 +- adapters/between/between.go | 12 +- adapters/between/between_test.go | 6 +- adapters/between/params_test.go | 2 +- adapters/beyondmedia/beyondmedia.go | 10 +- adapters/beyondmedia/beyondmedia_test.go | 6 +- adapters/beyondmedia/params_test.go | 2 +- adapters/bidder.go | 8 +- adapters/bidmachine/bidmachine.go | 12 +- adapters/bidmachine/bidmachine_test.go | 6 +- adapters/bidmachine/params_test.go | 2 +- adapters/bidmatic/bidmatic.go | 10 +- adapters/bidmatic/bidmatic_test.go | 6 +- adapters/bidmatic/params_test.go | 2 +- adapters/bidmyadz/bidmyadz.go | 10 +- adapters/bidmyadz/bidmyadz_test.go | 6 +- adapters/bidmyadz/params_test.go | 2 +- adapters/bidscube/bidscube.go | 10 +- adapters/bidscube/bidscube_test.go | 6 +- adapters/bidscube/params_test.go | 2 +- adapters/bidstack/bidstack.go | 8 +- adapters/bidstack/bidstack_test.go | 6 +- adapters/bidstack/params_test.go | 2 +- adapters/bidtheatre/bidtheatre.go | 10 +- adapters/bidtheatre/bidtheatre_test.go | 6 +- adapters/bidtheatre/params_test.go | 2 +- adapters/bigoad/bigoad.go | 12 +- adapters/bigoad/bigoad_test.go | 6 +- adapters/bigoad/param_test.go | 2 +- adapters/blasto/blasto.go | 12 +- adapters/blasto/blasto_test.go | 6 +- adapters/blasto/params_test.go | 2 +- adapters/bliink/bliink.go | 10 +- adapters/bliink/bliink_test.go | 6 +- adapters/bliink/params_test.go | 2 +- adapters/blis/blis.go | 14 +- adapters/blis/blis_test.go | 6 +- adapters/blis/params_test.go | 2 +- adapters/blue/blue.go | 10 +- adapters/blue/blue_test.go | 6 +- adapters/blue/params_test.go | 2 +- adapters/bluesea/bluesea.go | 10 +- adapters/bluesea/bluesea_test.go | 6 +- adapters/bluesea/params_test.go | 2 +- adapters/bmtm/brightmountainmedia.go | 10 +- adapters/bmtm/brightmountainmedia_test.go | 6 +- adapters/bmtm/params_test.go | 2 +- adapters/boldwin/boldwin.go | 10 +- adapters/boldwin/boldwin_test.go | 6 +- adapters/boldwin/params_test.go | 2 +- adapters/boldwin_rapid/boldwin_rapid.go | 10 +- adapters/boldwin_rapid/boldwin_rapid_test.go | 8 +- adapters/boldwin_rapid/params_test.go | 2 +- adapters/brave/brave.go | 12 +- adapters/brave/brave_test.go | 6 +- adapters/brave/params_test.go | 2 +- adapters/bwx/bwx.go | 12 +- adapters/bwx/bwx_test.go | 6 +- adapters/bwx/params_test.go | 2 +- .../cadent_aperture_mx/cadentaperturemx.go | 10 +- .../cadentaperturemx_test.go | 8 +- adapters/cadent_aperture_mx/params_test.go | 2 +- adapters/ccx/ccx.go | 10 +- adapters/ccx/ccx_test.go | 6 +- adapters/ccx/params_test.go | 2 +- adapters/clydo/clydo.go | 12 +- adapters/clydo/clydo_test.go | 6 +- adapters/clydo/params_test.go | 2 +- adapters/cointraffic/cointraffic.go | 8 +- adapters/cointraffic/cointraffic_test.go | 6 +- adapters/cointraffic/params_test.go | 2 +- adapters/coinzilla/coinzilla.go | 10 +- adapters/coinzilla/coinzilla_test.go | 6 +- adapters/coinzilla/params_test.go | 2 +- adapters/colossus/colossus.go | 10 +- adapters/colossus/colossus_test.go | 6 +- adapters/colossus/params_test.go | 2 +- adapters/compass/compass.go | 10 +- adapters/compass/compass_test.go | 6 +- adapters/compass/params_test.go | 2 +- adapters/concert/concert.go | 10 +- adapters/concert/concert_test.go | 6 +- adapters/concert/params_test.go | 2 +- adapters/connatix/connatix.go | 10 +- adapters/connatix/connatix_test.go | 6 +- adapters/connatix/models.go | 2 +- adapters/connatix/params_test.go | 2 +- adapters/connectad/connectad.go | 10 +- adapters/connectad/connectad_test.go | 6 +- adapters/connectad/params_test.go | 2 +- adapters/consumable/consumable.go | 10 +- adapters/consumable/consumable_test.go | 10 +- adapters/consumable/params_test.go | 2 +- adapters/contxtful/contxtful.go | 12 +- adapters/contxtful/contxtful_relay_test.go | 6 +- adapters/contxtful/contxtful_test.go | 10 +- adapters/contxtful/params_test.go | 2 +- adapters/conversant/conversant.go | 10 +- adapters/conversant/conversant_test.go | 6 +- adapters/copper6ssp/copper6ssp.go | 8 +- adapters/copper6ssp/copper6ssp_test.go | 6 +- adapters/copper6ssp/params_test.go | 2 +- adapters/cpmstar/cpmstar.go | 10 +- adapters/cpmstar/cpmstar_test.go | 6 +- adapters/cpmstar/params_test.go | 2 +- adapters/criteo/criteo.go | 10 +- adapters/criteo/criteo_test.go | 6 +- adapters/criteo/params_test.go | 2 +- adapters/cwire/cwire.go | 10 +- adapters/cwire/cwire_test.go | 6 +- adapters/cwire/params_test.go | 2 +- adapters/datablocks/datablocks.go | 12 +- adapters/datablocks/datablocks_test.go | 6 +- adapters/decenterads/decenterads.go | 10 +- adapters/decenterads/decenterads_test.go | 6 +- adapters/decenterads/params_test.go | 2 +- adapters/deepintent/deepintent.go | 10 +- adapters/deepintent/deepintent_test.go | 6 +- adapters/deepintent/params_test.go | 2 +- adapters/definemedia/definemedia.go | 10 +- adapters/definemedia/definemedia_test.go | 6 +- adapters/definemedia/params_test.go | 2 +- adapters/dianomi/dianomi.go | 10 +- adapters/dianomi/dianomi_test.go | 6 +- adapters/dianomi/params_test.go | 2 +- adapters/displayio/displayio.go | 12 +- adapters/displayio/displayio_test.go | 6 +- adapters/displayio/params_test.go | 2 +- adapters/dmx/dmx.go | 10 +- adapters/dmx/dmx_test.go | 8 +- adapters/dmx/params_test.go | 2 +- adapters/driftpixel/driftpixel.go | 12 +- adapters/driftpixel/driftpixel_test.go | 6 +- adapters/driftpixel/params_test.go | 2 +- adapters/e_volution/evolution.go | 10 +- adapters/e_volution/evolution_test.go | 6 +- adapters/e_volution/params_test.go | 2 +- adapters/edge226/edge226.go | 8 +- adapters/edge226/edge226_test.go | 6 +- adapters/edge226/params_test.go | 2 +- adapters/elementaltv/elementaltv.go | 12 +- adapters/elementaltv/elementaltv_test.go | 6 +- adapters/elementaltv/params_test.go | 2 +- adapters/emtv/emtv.go | 10 +- adapters/emtv/emtv_test.go | 6 +- adapters/emtv/params_test.go | 2 +- adapters/eplanning/eplanning.go | 10 +- adapters/eplanning/eplanning_test.go | 8 +- adapters/epom/epom.go | 10 +- adapters/epom/epom_test.go | 6 +- adapters/escalax/escalax.go | 12 +- adapters/escalax/escalax_test.go | 6 +- adapters/escalax/params_test.go | 2 +- adapters/exco/exco.go | 10 +- adapters/exco/exco_test.go | 6 +- adapters/exco/params_test.go | 2 +- adapters/feedad/feedad.go | 8 +- adapters/feedad/feedad_test.go | 6 +- adapters/feedad/params_test.go | 2 +- adapters/flatads/flatads.go | 12 +- adapters/flatads/flatads_test.go | 6 +- adapters/flatads/params_test.go | 2 +- adapters/flipp/flipp.go | 10 +- adapters/flipp/flipp_params.go | 2 +- adapters/flipp/flipp_test.go | 8 +- adapters/flipp/params_test.go | 2 +- adapters/freewheelssp/freewheelssp.go | 10 +- adapters/freewheelssp/freewheelssp_test.go | 6 +- adapters/frvradn/frvradn.go | 10 +- adapters/frvradn/frvradn_test.go | 6 +- adapters/frvradn/params_test.go | 2 +- adapters/fwssp/fwssp.go | 10 +- adapters/fwssp/fwssp_test.go | 6 +- adapters/fwssp/params_test.go | 2 +- adapters/gamma/gamma.go | 10 +- adapters/gamma/gamma_test.go | 6 +- adapters/gamma/params_test.go | 2 +- adapters/gamoshi/gamoshi.go | 10 +- adapters/gamoshi/gamoshi_test.go | 6 +- adapters/gamoshi/params_test.go | 2 +- adapters/globalsun/globalsun.go | 10 +- adapters/globalsun/globalsun_test.go | 6 +- adapters/globalsun/params_test.go | 2 +- adapters/goldbach/goldbach.go | 10 +- adapters/goldbach/goldbach_test.go | 6 +- adapters/goldbach/params_test.go | 2 +- adapters/grid/grid.go | 12 +- adapters/grid/grid_test.go | 6 +- adapters/gumgum/gumgum.go | 10 +- adapters/gumgum/gumgum_test.go | 6 +- adapters/gumgum/params_test.go | 2 +- adapters/huaweiads/huaweiads.go | 12 +- adapters/huaweiads/huaweiads_test.go | 6 +- adapters/huaweiads/params_test.go | 2 +- adapters/imds/imds.go | 12 +- adapters/imds/imds_test.go | 6 +- adapters/imds/params_test.go | 2 +- adapters/impactify/impactify.go | 10 +- adapters/impactify/impactify_test.go | 6 +- adapters/impactify/params_test.go | 2 +- adapters/improvedigital/improvedigital.go | 10 +- .../improvedigital/improvedigital_test.go | 6 +- adapters/improvedigital/params_test.go | 2 +- adapters/infoawarebidder.go | 6 +- adapters/infoawarebidder_test.go | 6 +- adapters/infytv/infytv.go | 10 +- adapters/infytv/infytv_test.go | 6 +- adapters/infytv/params_test.go | 2 +- adapters/inmobi/inmobi.go | 10 +- adapters/inmobi/inmobi_test.go | 6 +- adapters/insticator/insticator.go | 12 +- adapters/insticator/insticator_test.go | 6 +- adapters/insticator/params_test.go | 2 +- adapters/intenze/intenze.go | 12 +- adapters/intenze/intenze_test.go | 6 +- adapters/intenze/params_test.go | 2 +- .../interactiveoffers/interactiveoffers.go | 12 +- .../interactiveoffers_test.go | 6 +- adapters/interactiveoffers/params_test.go | 2 +- adapters/invibes/invibes.go | 14 +- adapters/invibes/invibes_test.go | 6 +- adapters/invibes/params_test.go | 2 +- adapters/iqx/iqx.go | 12 +- adapters/iqx/iqxtest_test.go | 6 +- adapters/iqx/params_test.go | 2 +- adapters/iqzone/iqzone.go | 10 +- adapters/iqzone/iqzone_test.go | 6 +- adapters/iqzone/params_test.go | 2 +- adapters/ix/ix.go | 14 +- adapters/ix/ix_test.go | 10 +- adapters/ix/params_test.go | 2 +- adapters/jixie/jixie.go | 10 +- adapters/jixie/jixie_test.go | 6 +- adapters/jixie/params_test.go | 2 +- adapters/kargo/kargo.go | 10 +- adapters/kargo/kargo_test.go | 6 +- adapters/kargo/params_test.go | 2 +- adapters/kayzen/kayzen.go | 12 +- adapters/kayzen/kayzen_test.go | 6 +- adapters/kayzen/params_test.go | 2 +- adapters/kidoz/kidoz.go | 10 +- adapters/kidoz/kidoz_test.go | 8 +- adapters/kidoz/params_test.go | 2 +- adapters/kiviads/kiviads.go | 10 +- adapters/kiviads/kiviads_test.go | 6 +- adapters/kiviads/params_test.go | 2 +- adapters/kobler/kobler.go | 10 +- adapters/kobler/kobler_test.go | 6 +- adapters/kobler/params_test.go | 2 +- adapters/krushmedia/krushmedia.go | 12 +- adapters/krushmedia/krushmedia_test.go | 6 +- adapters/krushmedia/params_test.go | 2 +- adapters/kueezrtb/kueezrtb.go | 10 +- adapters/kueezrtb/kueezrtb_test.go | 6 +- adapters/kueezrtb/params_test.go | 2 +- adapters/lemmadigital/lemmadigital.go | 12 +- adapters/lemmadigital/lemmadigital_test.go | 6 +- adapters/lemmadigital/params_test.go | 2 +- adapters/limelightDigital/limelightDigital.go | 12 +- .../limelightDigital/limelightDigital_test.go | 6 +- adapters/limelightDigital/params_test.go | 2 +- adapters/lm_kiviads/lmkiviads.go | 12 +- adapters/lm_kiviads/lmkiviads_test.go | 6 +- adapters/lm_kiviads/params_test.go | 2 +- adapters/lockerdome/lockerdome.go | 10 +- adapters/lockerdome/lockerdome_test.go | 6 +- adapters/lockerdome/params_test.go | 2 +- adapters/logan/logan.go | 10 +- adapters/logan/logan_test.go | 6 +- adapters/logan/params_test.go | 2 +- adapters/logicad/logicad.go | 10 +- adapters/logicad/logicad_test.go | 6 +- adapters/logicad/params_test.go | 2 +- adapters/loopme/loopme.go | 8 +- adapters/loopme/loopme_test.go | 6 +- adapters/loopme/params_test.go | 2 +- adapters/loyal/loyal.go | 8 +- adapters/loyal/loyal_test.go | 6 +- adapters/loyal/params_test.go | 2 +- adapters/lunamedia/lunamedia.go | 12 +- adapters/lunamedia/lunamedia_test.go | 6 +- adapters/lunamedia/params_test.go | 2 +- adapters/mabidder/mabidder.go | 8 +- adapters/mabidder/mabidder_test.go | 6 +- adapters/mabidder/params_test.go | 2 +- adapters/madsense/madsense.go | 10 +- adapters/madsense/madsense_test.go | 6 +- adapters/madsense/params_test.go | 2 +- adapters/madsense/utils.go | 8 +- adapters/madvertise/madvertise.go | 12 +- adapters/madvertise/madvertise_test.go | 6 +- adapters/madvertise/params_test.go | 2 +- adapters/marsmedia/marsmedia.go | 10 +- adapters/marsmedia/marsmedia_test.go | 6 +- adapters/marsmedia/params_test.go | 2 +- adapters/mediago/mediago.go | 12 +- adapters/mediago/mediago_test.go | 6 +- adapters/mediago/params_test.go | 2 +- adapters/medianet/medianet.go | 10 +- adapters/medianet/medianet_test.go | 6 +- adapters/medianet/params_test.go | 2 +- adapters/mediasquare/mediasquare.go | 10 +- adapters/mediasquare/mediasquare_test.go | 8 +- adapters/mediasquare/params_test.go | 2 +- adapters/mediasquare/parsers.go | 2 +- adapters/mediasquare/structs.go | 6 +- adapters/mediasquare/utils.go | 4 +- adapters/melozen/melozen.go | 12 +- adapters/melozen/melozen_test.go | 6 +- adapters/melozen/params_test.go | 2 +- adapters/metax/metax.go | 14 +- adapters/metax/metax_test.go | 10 +- adapters/metax/params_test.go | 2 +- adapters/mgid/mgid.go | 10 +- adapters/mgid/mgid_test.go | 6 +- adapters/mgidX/mgidX.go | 8 +- adapters/mgidX/mgidX_test.go | 6 +- adapters/mgidX/params_test.go | 2 +- adapters/minutemedia/minutemedia.go | 10 +- adapters/minutemedia/minutemedia_test.go | 6 +- adapters/missena/missena.go | 14 +- adapters/missena/missena_test.go | 6 +- adapters/missena/params_test.go | 2 +- adapters/mobfoxpb/mobfoxpb.go | 10 +- adapters/mobfoxpb/mobfoxpb_test.go | 6 +- adapters/mobfoxpb/params_test.go | 2 +- adapters/mobilefuse/mobilefuse.go | 10 +- adapters/mobilefuse/mobilefuse_test.go | 6 +- adapters/mobilefuse/params_test.go | 2 +- adapters/mobkoi/mobkoi.go | 8 +- adapters/mobkoi/mobkoi_test.go | 6 +- adapters/mobkoi/params_test.go | 2 +- adapters/motorik/motorik.go | 12 +- adapters/motorik/motorik_test.go | 6 +- adapters/motorik/params_test.go | 2 +- adapters/msft/models.go | 2 +- adapters/msft/msft.go | 12 +- adapters/msft/msft_test.go | 6 +- adapters/msft/params_test.go | 2 +- adapters/nativery/nativery.go | 12 +- adapters/nativery/nativery_test.go | 6 +- adapters/nativery/params_test.go | 2 +- adapters/nativo/nativo.go | 6 +- adapters/nativo/nativo_test.go | 6 +- adapters/nextmillennium/nextmillennium.go | 12 +- .../nextmillennium/nextmillennium_test.go | 6 +- adapters/nextmillennium/params_test.go | 2 +- adapters/nexx360/nexx360.go | 12 +- adapters/nexx360/nexx360_test.go | 6 +- adapters/nexx360/params_test.go | 2 +- adapters/nobid/nobid.go | 10 +- adapters/nobid/nobid_test.go | 6 +- adapters/nobid/params_test.go | 2 +- adapters/ogury/ogury.go | 10 +- adapters/ogury/ogury_test.go | 6 +- adapters/ogury/param_test.go | 2 +- adapters/oms/oms.go | 10 +- adapters/oms/oms_test.go | 6 +- adapters/oms/params_test.go | 2 +- adapters/onetag/onetag.go | 12 +- adapters/onetag/onetag_test.go | 6 +- adapters/onetag/params_test.go | 2 +- adapters/openweb/openweb.go | 10 +- adapters/openweb/openweb_test.go | 6 +- adapters/openweb/params_test.go | 2 +- adapters/openx/openx.go | 10 +- adapters/openx/openx_test.go | 8 +- adapters/openx/params_test.go | 2 +- adapters/operaads/operaads.go | 14 +- adapters/operaads/operaads_test.go | 6 +- adapters/operaads/params_test.go | 2 +- adapters/optidigital/optidigital.go | 10 +- adapters/optidigital/optidigital_test.go | 6 +- adapters/optidigital/params_test.go | 2 +- adapters/oraki/oraki.go | 8 +- adapters/oraki/oraki_test.go | 6 +- adapters/oraki/params_test.go | 2 +- adapters/orbidder/orbidder.go | 10 +- adapters/orbidder/orbidder_test.go | 8 +- adapters/orbidder/params_test.go | 2 +- adapters/outbrain/outbrain.go | 10 +- adapters/outbrain/outbrain_test.go | 6 +- adapters/outbrain/params_test.go | 2 +- adapters/ownadx/ownadx.go | 12 +- adapters/ownadx/ownadx_test.go | 6 +- adapters/pangle/pangle.go | 10 +- adapters/pangle/pangle_test.go | 6 +- adapters/pangle/param_test.go | 2 +- adapters/pgamssp/params_test.go | 2 +- adapters/pgamssp/pgamssp.go | 8 +- adapters/pgamssp/pgamssp_test.go | 6 +- adapters/playdigo/params_test.go | 2 +- adapters/playdigo/playdigo.go | 8 +- adapters/playdigo/playdigo_test.go | 6 +- adapters/pubmatic/params_test.go | 2 +- adapters/pubmatic/pubmatic.go | 12 +- adapters/pubmatic/pubmatic_test.go | 10 +- adapters/pubnative/pubnative.go | 12 +- adapters/pubnative/pubnative_test.go | 6 +- adapters/pubrise/params_test.go | 2 +- adapters/pubrise/pubrise.go | 8 +- adapters/pubrise/pubrise_test.go | 6 +- adapters/pulsepoint/params_test.go | 2 +- adapters/pulsepoint/pulsepoint.go | 10 +- adapters/pulsepoint/pulsepoint_test.go | 6 +- adapters/pwbid/params_test.go | 2 +- adapters/pwbid/pwbid.go | 10 +- adapters/pwbid/pwbid_test.go | 6 +- adapters/qt/params_test.go | 2 +- adapters/qt/qt.go | 8 +- adapters/qt/qt_test.go | 6 +- adapters/readpeak/params_test.go | 2 +- adapters/readpeak/readpeak.go | 10 +- adapters/readpeak/readpeak_test.go | 6 +- adapters/rediads/params_test.go | 2 +- adapters/rediads/rediads.go | 10 +- adapters/rediads/rediads_test.go | 6 +- adapters/relevantdigital/params_test.go | 2 +- adapters/relevantdigital/relevantdigital.go | 12 +- .../relevantdigital/relevantdigital_test.go | 6 +- adapters/resetdigital/params_test.go | 2 +- adapters/resetdigital/resetdigital.go | 8 +- adapters/resetdigital/resetdigital_test.go | 10 +- adapters/response.go | 2 +- adapters/response_test.go | 2 +- adapters/revcontent/revcontent.go | 10 +- adapters/revcontent/revcontent_test.go | 6 +- adapters/richaudience/params_test.go | 2 +- adapters/richaudience/richaudience.go | 10 +- adapters/richaudience/richaudience_test.go | 8 +- adapters/rise/rise.go | 8 +- adapters/rise/rise_test.go | 6 +- adapters/roulax/roulax.go | 10 +- adapters/roulax/roulax_test.go | 6 +- adapters/rtbhouse/rtbhouse.go | 10 +- adapters/rtbhouse/rtbhouse_test.go | 6 +- adapters/rubicon/rubicon.go | 16 +- adapters/rubicon/rubicon_test.go | 12 +- adapters/sa_lunamedia/params_test.go | 2 +- adapters/sa_lunamedia/salunamedia.go | 10 +- adapters/sa_lunamedia/salunamedia_test.go | 6 +- adapters/seedingAlliance/params_test.go | 2 +- adapters/seedingAlliance/seedingAlliance.go | 12 +- .../seedingAlliance/seedingAlliance_test.go | 8 +- adapters/seedtag/params_test.go | 2 +- adapters/seedtag/seedtag.go | 8 +- adapters/seedtag/seedtag_test.go | 6 +- adapters/sharethrough/params_test.go | 2 +- adapters/sharethrough/sharethrough.go | 12 +- adapters/sharethrough/sharethrough_test.go | 6 +- adapters/showheroes/params_test.go | 2 +- adapters/showheroes/showheroes.go | 12 +- adapters/showheroes/showheroes_test.go | 6 +- adapters/silvermob/params_test.go | 2 +- adapters/silvermob/silvermob.go | 12 +- adapters/silvermob/silvermob_test.go | 6 +- adapters/silverpush/params_test.go | 2 +- adapters/silverpush/silverpush.go | 12 +- adapters/silverpush/silverpush_test.go | 8 +- adapters/smaato/native.go | 4 +- adapters/smaato/params_test.go | 2 +- adapters/smaato/smaato.go | 14 +- adapters/smaato/smaato_test.go | 10 +- adapters/smartadserver/params_test.go | 2 +- adapters/smartadserver/smartadserver.go | 10 +- adapters/smartadserver/smartadserver_test.go | 6 +- adapters/smarthub/params_test.go | 2 +- adapters/smarthub/smarthub.go | 12 +- adapters/smarthub/smarthub_test.go | 6 +- adapters/smartrtb/smartrtb.go | 12 +- adapters/smartrtb/smartrtb_test.go | 6 +- adapters/smartx/params_test.go | 2 +- adapters/smartx/smartx.go | 8 +- adapters/smartx/smartx_test.go | 6 +- adapters/smartyads/params_test.go | 2 +- adapters/smartyads/smartyads.go | 12 +- adapters/smartyads/smartyads_test.go | 6 +- adapters/smilewanted/params_test.go | 2 +- adapters/smilewanted/smilewanted.go | 10 +- adapters/smilewanted/smilewanted_test.go | 8 +- adapters/smoot/params_test.go | 2 +- adapters/smoot/smoot.go | 8 +- adapters/smoot/smoot_test.go | 6 +- adapters/smrtconnect/smrtconnect.go | 12 +- adapters/smrtconnect/smrtconnect_test.go | 6 +- adapters/sonobi/params_test.go | 2 +- adapters/sonobi/sonobi.go | 10 +- adapters/sonobi/sonobi_test.go | 6 +- adapters/sovrn/params_test.go | 2 +- adapters/sovrn/sovrn.go | 10 +- adapters/sovrn/sovrn_test.go | 6 +- adapters/sovrnXsp/params_test.go | 2 +- adapters/sovrnXsp/sovrnXsp.go | 10 +- adapters/sovrnXsp/sovrnXsp_test.go | 6 +- adapters/sparteo/params_test.go | 2 +- adapters/sparteo/sparteo.go | 10 +- adapters/sparteo/sparteo_test.go | 6 +- adapters/sspBC/sspbc.go | 12 +- adapters/sspBC/sspbc_test.go | 10 +- adapters/startio/startio.go | 10 +- adapters/startio/startio_test.go | 6 +- adapters/stroeerCore/params_test.go | 2 +- adapters/stroeerCore/stroeercore.go | 10 +- adapters/stroeerCore/stroeercore_test.go | 6 +- adapters/taboola/params_test.go | 2 +- adapters/taboola/taboola.go | 12 +- adapters/taboola/taboola_test.go | 6 +- adapters/tappx/params_test.go | 2 +- adapters/tappx/tappx.go | 12 +- adapters/tappx/tappx_test.go | 6 +- adapters/teads/teads.go | 12 +- adapters/teads/teads_test.go | 6 +- adapters/telaria/params_test.go | 2 +- adapters/telaria/telaria.go | 10 +- adapters/telaria/telaria_test.go | 6 +- adapters/teqblaze/params_test.go | 2 +- adapters/teqblaze/teqblaze.go | 8 +- adapters/teqblaze/teqblaze_test.go | 6 +- adapters/theadx/params_test.go | 2 +- adapters/theadx/theadx.go | 10 +- adapters/theadx/theadx_test.go | 6 +- adapters/thetradedesk/params_test.go | 2 +- adapters/thetradedesk/thetradedesk.go | 10 +- adapters/thetradedesk/thetradedesk_test.go | 8 +- adapters/tpmn/params_test.go | 2 +- adapters/tpmn/tpmn.go | 8 +- adapters/tpmn/tpmn_test.go | 6 +- adapters/tradplus/params_test.go | 2 +- adapters/tradplus/tradplus.go | 12 +- adapters/tradplus/tradplus_test.go | 6 +- adapters/trafficgate/params_test.go | 2 +- adapters/trafficgate/trafficgate.go | 12 +- adapters/trafficgate/trafficgate_test.go | 6 +- adapters/triplelift/triplelift.go | 10 +- adapters/triplelift/triplelift_test.go | 6 +- adapters/triplelift_native/params_test.go | 2 +- .../triplelift_native/triplelift_native.go | 10 +- .../triplelift_native_test.go | 6 +- adapters/trustedstack/params_test.go | 2 +- adapters/trustedstack/trustedstack.go | 8 +- adapters/trustedstack/trustedstack_test.go | 6 +- adapters/trustx/params_test.go | 2 +- adapters/trustx/trustx.go | 10 +- adapters/trustx/trustx_test.go | 6 +- adapters/ucfunnel/params_test.go | 2 +- adapters/ucfunnel/ucfunnel.go | 10 +- adapters/ucfunnel/ucfunnel_test.go | 6 +- adapters/undertone/params_test.go | 2 +- adapters/undertone/undertone.go | 10 +- adapters/undertone/undertone_test.go | 6 +- adapters/unicorn/params_test.go | 2 +- adapters/unicorn/unicorn.go | 10 +- adapters/unicorn/unicorn_test.go | 6 +- adapters/unruly/params_test.go | 2 +- adapters/unruly/unruly.go | 10 +- adapters/unruly/unruly_test.go | 6 +- adapters/vidazoo/params_test.go | 2 +- adapters/vidazoo/vidazoo.go | 10 +- adapters/vidazoo/vidazoo_test.go | 6 +- adapters/videobyte/params_test.go | 2 +- adapters/videobyte/videobyte.go | 10 +- adapters/videobyte/videobyte_test.go | 4 +- adapters/videoheroes/params_test.go | 2 +- adapters/videoheroes/videoheroes.go | 12 +- adapters/videoheroes/videoheroes_test.go | 6 +- adapters/vidoomy/params_test.go | 2 +- adapters/vidoomy/vidoomy.go | 12 +- adapters/vidoomy/vidoomy_test.go | 6 +- adapters/visiblemeasures/params_test.go | 2 +- adapters/visiblemeasures/visiblemeasures.go | 10 +- .../visiblemeasures/visiblemeasures_test.go | 6 +- adapters/visx/params_test.go | 2 +- adapters/visx/visx.go | 10 +- adapters/visx/visx_test.go | 6 +- adapters/vox/params_test.go | 2 +- adapters/vox/vox.go | 8 +- adapters/vox/vox_test.go | 6 +- adapters/vrtcal/params_test.go | 2 +- adapters/vrtcal/vrtcal.go | 10 +- adapters/vrtcal/vrtcal_test.go | 6 +- adapters/vungle/param_test.go | 2 +- adapters/vungle/vungle.go | 8 +- adapters/vungle/vungle_test.go | 6 +- adapters/xeworks/params_test.go | 2 +- adapters/xeworks/xeworks.go | 12 +- adapters/xeworks/xeworks_test.go | 6 +- adapters/yahooAds/params_test.go | 2 +- adapters/yahooAds/yahooAds.go | 12 +- adapters/yahooAds/yahooAds_test.go | 6 +- adapters/yandex/params_test.go | 2 +- adapters/yandex/yandex.go | 12 +- adapters/yandex/yandex_test.go | 6 +- adapters/yeahmobi/params_test.go | 2 +- adapters/yeahmobi/yeahmobi.go | 12 +- adapters/yeahmobi/yeahmobi_test.go | 6 +- adapters/yieldlab/params_test.go | 2 +- adapters/yieldlab/types.go | 2 +- adapters/yieldlab/yieldlab.go | 12 +- adapters/yieldlab/yieldlab_test.go | 6 +- adapters/yieldmo/params_test.go | 2 +- adapters/yieldmo/yieldmo.go | 10 +- adapters/yieldmo/yieldmo_test.go | 6 +- adapters/yieldone/params_test.go | 2 +- adapters/yieldone/yieldone.go | 10 +- adapters/yieldone/yieldone_test.go | 6 +- adapters/zentotem/zentotem.go | 6 +- adapters/zentotem/zentotem_test.go | 6 +- adapters/zeroclickfraud/zeroclickfraud.go | 12 +- .../zeroclickfraud/zeroclickfraud_test.go | 6 +- adapters/zeta_global_ssp/params_test.go | 2 +- adapters/zeta_global_ssp/zeta_global_ssp.go | 12 +- .../zeta_global_ssp/zeta_global_ssp_test.go | 6 +- adapters/zmaticoo/params_test.go | 2 +- adapters/zmaticoo/zmaticoo.go | 10 +- adapters/zmaticoo/zmaticoo_test.go | 6 +- adservertargeting/adservertargeting.go | 2 +- adservertargeting/adservertargeting_test.go | 4 +- adservertargeting/reqcache.go | 2 +- adservertargeting/requestlookup.go | 2 +- adservertargeting/requestlookup_test.go | 2 +- adservertargeting/respdataprocessor.go | 4 +- adservertargeting/respdataprocessor_test.go | 2 +- adservertargeting/utils.go | 4 +- amp/parse.go | 8 +- amp/parse_test.go | 8 +- analytics/agma/agma_module.go | 8 +- analytics/agma/agma_module_test.go | 6 +- analytics/agma/model.go | 4 +- analytics/agma/model_test.go | 2 +- analytics/agma/sender.go | 6 +- analytics/agma/sender_test.go | 2 +- analytics/build/build.go | 20 +- analytics/build/build_test.go | 12 +- analytics/core.go | 6 +- analytics/filesystem/file_module.go | 6 +- analytics/filesystem/file_module_test.go | 4 +- analytics/filesystem/model.go | 8 +- analytics/pubstack/config.go | 2 +- analytics/pubstack/configupdate.go | 2 +- .../pubstack/eventchannel/eventchannel.go | 2 +- analytics/pubstack/eventchannel/sender.go | 2 +- analytics/pubstack/helpers/json.go | 4 +- analytics/pubstack/helpers/json_test.go | 2 +- analytics/pubstack/helpers/model.go | 8 +- analytics/pubstack/pubstack_module.go | 8 +- analytics/pubstack/pubstack_module_test.go | 4 +- analytics/runner.go | 2 +- bidadjustment/apply.go | 4 +- bidadjustment/apply_test.go | 4 +- bidadjustment/build_rules.go | 4 +- bidadjustment/build_rules_test.go | 4 +- bidadjustment/validate.go | 2 +- bidadjustment/validate_test.go | 2 +- config/account.go | 4 +- config/account_module_decoder.go | 2 +- config/account_test.go | 2 +- config/bidderinfo.go | 10 +- config/bidderinfo_test.go | 4 +- config/compression.go | 2 +- config/compression_test.go | 2 +- config/config.go | 8 +- config/config_test.go | 4 +- config/stored_requests.go | 2 +- config/structlog.go | 2 +- currency/currency.go | 2 +- currency/currency_test.go | 6 +- currency/rate_converter.go | 8 +- currency/rate_converter_test.go | 2 +- currency/rates_test.go | 2 +- currency/validation.go | 4 +- currency/validation_test.go | 4 +- dsa/validate.go | 6 +- dsa/validate_test.go | 6 +- dsa/writer.go | 4 +- dsa/writer_test.go | 6 +- endpoints/cookie_sync.go | 34 +- endpoints/cookie_sync_test.go | 22 +- endpoints/currency_rates.go | 6 +- endpoints/currency_rates_test.go | 2 +- endpoints/events/account_test.go | 8 +- endpoints/events/event.go | 18 +- endpoints/events/event_test.go | 12 +- endpoints/events/vtrack.go | 20 +- endpoints/events/vtrack_test.go | 10 +- endpoints/getuids.go | 4 +- endpoints/getuids_test.go | 2 +- endpoints/info/bidders.go | 6 +- endpoints/info/bidders_detail.go | 8 +- endpoints/info/bidders_detail_test.go | 6 +- endpoints/info/bidders_test.go | 2 +- endpoints/openrtb2/amp_auction.go | 42 +- endpoints/openrtb2/amp_auction_test.go | 34 +- endpoints/openrtb2/auction.go | 58 +- endpoints/openrtb2/auction_benchmark_test.go | 24 +- endpoints/openrtb2/auction_test.go | 38 +- endpoints/openrtb2/interstitial.go | 6 +- endpoints/openrtb2/interstitial_test.go | 2 +- endpoints/openrtb2/test_utils.go | 46 +- endpoints/openrtb2/video_auction.go | 42 +- endpoints/openrtb2/video_auction_test.go | 30 +- endpoints/setuid.go | 26 +- endpoints/setuid_test.go | 20 +- endpoints/version.go | 4 +- exchange/adapter_builders.go | 522 +++++++++--------- exchange/adapter_util.go | 8 +- exchange/adapter_util_test.go | 12 +- exchange/auction.go | 10 +- exchange/auction_response.go | 2 +- exchange/auction_test.go | 12 +- exchange/bidder.go | 28 +- exchange/bidder_health_test.go | 6 +- exchange/bidder_test.go | 28 +- exchange/bidder_validate_bids.go | 12 +- exchange/bidder_validate_bids_test.go | 12 +- exchange/entities/entities.go | 2 +- exchange/events.go | 12 +- exchange/events_test.go | 4 +- exchange/exchange.go | 50 +- exchange/exchange_test.go | 48 +- exchange/non_bid_reason.go | 2 +- exchange/non_bid_reason_test.go | 2 +- exchange/price_granularity.go | 4 +- exchange/price_granularity_test.go | 6 +- exchange/seat_non_bids.go | 4 +- exchange/seat_non_bids_test.go | 4 +- exchange/targeting.go | 2 +- exchange/targeting_test.go | 20 +- exchange/tmax_adjustments.go | 2 +- exchange/tmax_adjustments_test.go | 2 +- exchange/utils.go | 28 +- exchange/utils_test.go | 18 +- experiment/adscert/SignerLogger.go | 2 +- experiment/adscert/inprocesssigner.go | 2 +- experiment/adscert/remotesigner.go | 2 +- experiment/adscert/signer.go | 2 +- experiment/adscert/signer_test.go | 2 +- firstpartydata/first_party_data.go | 8 +- firstpartydata/first_party_data_test.go | 6 +- floors/enforce.go | 8 +- floors/enforce_test.go | 10 +- floors/fetcher.go | 10 +- floors/fetcher_test.go | 12 +- floors/floors.go | 8 +- floors/floors_test.go | 10 +- floors/rule.go | 8 +- floors/rule_test.go | 6 +- floors/validate.go | 4 +- floors/validate_test.go | 4 +- gdpr/aggregated_config.go | 4 +- gdpr/aggregated_config_test.go | 4 +- gdpr/basic_enforcement_test.go | 2 +- gdpr/full_enforcement_test.go | 4 +- gdpr/gdpr.go | 6 +- gdpr/gdpr_test.go | 6 +- gdpr/gvl_vendor_ids.go | 6 +- gdpr/gvl_vendor_ids_test.go | 2 +- gdpr/impl.go | 4 +- gdpr/impl_test.go | 6 +- gdpr/purpose_config.go | 2 +- gdpr/purpose_config_test.go | 2 +- gdpr/purpose_enforcer.go | 4 +- gdpr/purpose_enforcer_test.go | 4 +- gdpr/signal.go | 2 +- gdpr/utils.go | 4 +- gdpr/utils_test.go | 4 +- gdpr/vendorlist-fetching.go | 6 +- gdpr/vendorlist-fetching_test.go | 6 +- go.mod | 4 +- hooks/empty_plan.go | 4 +- hooks/hookanalytics/analytics_test.go | 2 +- hooks/hookexecution/context.go | 8 +- hooks/hookexecution/enricher.go | 4 +- hooks/hookexecution/enricher_test.go | 8 +- hooks/hookexecution/errors.go | 2 +- hooks/hookexecution/execution.go | 18 +- hooks/hookexecution/execution_test.go | 8 +- hooks/hookexecution/executor.go | 16 +- hooks/hookexecution/executor_test.go | 22 +- hooks/hookexecution/mocks_test.go | 6 +- hooks/hookexecution/outcome.go | 2 +- hooks/hookexecution/test_utils.go | 2 +- hooks/hookstage/allprocessedbidresponses.go | 4 +- hooks/hookstage/bidderrequest.go | 2 +- hooks/hookstage/bidderrequest_mutations.go | 2 +- hooks/hookstage/invocation.go | 2 +- hooks/hookstage/processedauctionrequest.go | 2 +- .../processedauctionrequest_mutations.go | 2 +- .../processedauctionrequest_mutations_test.go | 2 +- hooks/hookstage/rawbidderresponse.go | 2 +- .../hookstage/rawbidderresponse_mutations.go | 2 +- hooks/plan.go | 6 +- hooks/plan_test.go | 6 +- hooks/repo.go | 2 +- hooks/repo_test.go | 2 +- injector/injector.go | 4 +- injector/injector_test.go | 8 +- macros/provider.go | 4 +- macros/provider_test.go | 4 +- macros/string_index_based_replacer_test.go | 4 +- main.go | 16 +- main_test.go | 2 +- metrics/config/metrics.go | 8 +- metrics/config/metrics_test.go | 6 +- metrics/go_metrics.go | 6 +- metrics/go_metrics_test.go | 4 +- metrics/metrics.go | 2 +- metrics/metrics_mock.go | 2 +- metrics/prometheus/preload.go | 4 +- metrics/prometheus/prometheus.go | 6 +- metrics/prometheus/prometheus_test.go | 6 +- modules/builder.go | 8 +- .../fiftyonedegrees/devicedetection/config.go | 2 +- .../devicedetection/device_info_extractor.go | 2 +- .../devicedetection/evidence_extractor.go | 2 +- .../evidence_extractor_test.go | 2 +- .../hook_auction_entrypoint.go | 4 +- .../hook_raw_auction_request.go | 4 +- .../fiftyonedegrees/devicedetection/module.go | 4 +- .../devicedetection/module_no_cgo_test.go | 2 +- .../devicedetection/module_test.go | 4 +- .../fiftyonedegrees/devicedetection/no-cgo.go | 2 +- modules/generator/builder.tmpl | 2 +- modules/helpers.go | 4 +- modules/moduledeps/deps.go | 2 +- modules/modules.go | 10 +- modules/modules_test.go | 8 +- modules/prebid/ortb2blocking/analytics.go | 4 +- modules/prebid/ortb2blocking/config.go | 2 +- .../ortb2blocking/hook_bidderrequest.go | 6 +- .../ortb2blocking/hook_bidderrequest_test.go | 6 +- .../ortb2blocking/hook_raw_bidder_response.go | 6 +- modules/prebid/ortb2blocking/module.go | 4 +- modules/prebid/ortb2blocking/module_test.go | 12 +- .../rulesengine/bidder_config_ruleset.go | 2 +- .../bidder_config_ruleset_builder.go | 4 +- .../bidder_config_ruleset_builder_test.go | 2 +- .../rulesengine/bidder_config_ruleset_test.go | 4 +- modules/prebid/rulesengine/cache.go | 2 +- modules/prebid/rulesengine/cache_entry.go | 8 +- .../prebid/rulesengine/cache_entry_test.go | 8 +- modules/prebid/rulesengine/config/config.go | 4 +- .../rulesengine/hook_processed_auction.go | 6 +- .../hook_processed_auction_test.go | 6 +- modules/prebid/rulesengine/module.go | 6 +- modules/prebid/rulesengine/module_test.go | 2 +- .../prebid/rulesengine/result_functions.go | 8 +- .../rulesengine/result_functions_test.go | 8 +- modules/prebid/rulesengine/tree_builder.go | 4 +- .../prebid/rulesengine/tree_builder_test.go | 8 +- modules/prebid/rulesengine/tree_manager.go | 2 +- .../prebid/rulesengine/tree_manager_test.go | 2 +- modules/prebid/rulesengine/tree_test.go | 6 +- modules/scope3/rtd/masking.go | 4 +- modules/scope3/rtd/module.go | 12 +- modules/scope3/rtd/module_test.go | 8 +- modules/shutdown.go | 2 +- openrtb_ext/convert_down_test.go | 4 +- openrtb_ext/deal_tier.go | 2 +- openrtb_ext/deal_tier_test.go | 2 +- openrtb_ext/device.go | 2 +- openrtb_ext/device_test.go | 2 +- openrtb_ext/floors.go | 2 +- openrtb_ext/floors_test.go | 2 +- openrtb_ext/imp_appnexus.go | 2 +- openrtb_ext/imp_appnexus_test.go | 2 +- openrtb_ext/imp_connectad.go | 2 +- openrtb_ext/imp_freewheelssp.go | 2 +- openrtb_ext/imp_goldbach.go | 2 +- openrtb_ext/imp_pulsepoint.go | 2 +- openrtb_ext/multibid_test.go | 2 +- openrtb_ext/regs_test.go | 2 +- openrtb_ext/request.go | 4 +- openrtb_ext/request_test.go | 4 +- openrtb_ext/request_wrapper.go | 4 +- openrtb_ext/request_wrapper_test.go | 4 +- openrtb_ext/site_test.go | 4 +- openrtb_ext/supplyChain.go | 2 +- openrtb_ext/supplyChain_test.go | 2 +- ortb/clone.go | 2 +- ortb/clone_test.go | 2 +- ortb/default.go | 4 +- ortb/default_test.go | 8 +- ortb/request_validator.go | 6 +- ortb/request_validator_banner.go | 2 +- ortb/request_validator_banner_test.go | 2 +- ortb/request_validator_native.go | 4 +- ortb/request_validator_test.go | 4 +- ortb/request_validator_video_test.go | 2 +- pbs/usersync.go | 6 +- prebid_cache_client/client.go | 6 +- prebid_cache_client/client_test.go | 8 +- privacy/activitycontrol.go | 4 +- privacy/activitycontrol_test.go | 6 +- privacy/ccpa/consentwriter_test.go | 2 +- privacy/ccpa/parsedpolicy.go | 2 +- privacy/ccpa/policy.go | 6 +- privacy/ccpa/policy_test.go | 2 +- privacy/lmt/ios.go | 4 +- privacy/lmt/ios_test.go | 2 +- privacy/rule_condition_test.go | 2 +- privacy/scrubber.go | 8 +- privacy/scrubber_test.go | 4 +- privacysandbox/topics.go | 4 +- privacysandbox/topics_test.go | 2 +- router/admin.go | 6 +- router/aspects/request_timeout_handler.go | 4 +- .../aspects/request_timeout_handler_test.go | 4 +- router/router.go | 60 +- router/router_test.go | 6 +- rules/schema_functions.go | 8 +- rules/schema_functions_test.go | 8 +- schain/schain.go | 2 +- schain/schain_test.go | 2 +- schain/schainwriter.go | 2 +- schain/schainwriter_test.go | 4 +- server/listener.go | 4 +- server/listener_test.go | 4 +- server/prometheus.go | 6 +- server/server.go | 8 +- server/server_test.go | 4 +- .../backends/db_fetcher/fetcher.go | 6 +- .../backends/db_fetcher/fetcher_test.go | 2 +- .../backends/db_provider/db_provider.go | 4 +- .../backends/db_provider/db_provider_mock.go | 2 +- .../backends/db_provider/mysql_dbprovider.go | 2 +- .../db_provider/mysql_dbprovider_test.go | 2 +- .../db_provider/postgres_dbprovider.go | 2 +- .../db_provider/postgres_dbprovider_test.go | 2 +- .../backends/empty_fetcher/fetcher.go | 2 +- .../backends/file_fetcher/fetcher.go | 4 +- .../backends/file_fetcher/fetcher_test.go | 4 +- .../backends/http_fetcher/fetcher.go | 6 +- .../backends/http_fetcher/fetcher_test.go | 2 +- stored_requests/caches/cachestest/reliable.go | 2 +- stored_requests/caches/memory/cache.go | 4 +- stored_requests/caches/memory/cache_test.go | 4 +- stored_requests/caches/memory/maps.go | 2 +- stored_requests/config/config.go | 32 +- stored_requests/config/config_test.go | 16 +- stored_requests/events/api/api.go | 4 +- stored_requests/events/api/api_test.go | 6 +- stored_requests/events/database/database.go | 12 +- .../events/database/database_test.go | 8 +- stored_requests/events/events.go | 2 +- stored_requests/events/events_test.go | 4 +- stored_requests/events/http/http.go | 6 +- stored_requests/events/http/http_test.go | 2 +- stored_requests/fetcher.go | 2 +- stored_requests/fetcher_test.go | 4 +- stored_responses/stored_responses.go | 4 +- stored_responses/stored_responses_test.go | 2 +- usersync/chooser.go | 4 +- usersync/chooser_test.go | 8 +- usersync/cookie.go | 6 +- usersync/cookie_test.go | 4 +- usersync/decoder.go | 2 +- usersync/encoder.go | 2 +- usersync/syncer.go | 4 +- usersync/syncer_test.go | 4 +- usersync/syncersbuilder.go | 2 +- usersync/syncersbuilder_test.go | 4 +- util/httputil/httputil.go | 2 +- util/httputil/httputil_test.go | 2 +- util/jsonutil/forcestring.go | 2 +- util/jsonutil/forcestring_test.go | 2 +- util/jsonutil/jsonutil.go | 2 +- util/jsonutil/merge.go | 2 +- util/task/ticker_task_test.go | 2 +- version/xprebidheader.go | 2 +- version/xprebidheader_test.go | 4 +- 1122 files changed, 3871 insertions(+), 3873 deletions(-) diff --git a/Dockerfile b/Dockerfile index fe7cec5e16..6c0295688b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ RUN go mod tidy RUN go mod vendor ARG TEST="true" RUN if [ "$TEST" != "false" ]; then ./validate.sh ; fi -RUN go build -mod=vendor -ldflags "-X github.com/prebid/prebid-server/v3/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/v3/version.Rev=`git rev-parse HEAD`" . +RUN go build -mod=vendor -ldflags "-X github.com/prebid/prebid-server/v4/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/v4/version.Rev=`git rev-parse HEAD`" . FROM ubuntu:22.04 AS release LABEL maintainer="hans.hjort@xandr.com" diff --git a/Makefile b/Makefile index 8b68afe3be..327a4acd23 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ test: deps ifeq "$(adapter)" "" ./validate.sh else - go test github.com/prebid/prebid-server/v3/adapters/$(adapter) -bench=. + go test github.com/prebid/prebid-server/v4/adapters/$(adapter) -bench=. endif # build-modules generates modules/builder.go file which provides a list of all available modules diff --git a/account/account.go b/account/account.go index 0087548cc7..87597e5fed 100644 --- a/account/account.go +++ b/account/account.go @@ -6,13 +6,13 @@ import ( "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // GetAccount looks up the config.Account object referenced by the given accountID, with access rules applied diff --git a/account/account_test.go b/account/account_test.go index c8b17b53ff..15963e3d0b 100644 --- a/account/account_test.go +++ b/account/account_test.go @@ -6,13 +6,13 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/adapters/33across/33across.go b/adapters/33across/33across.go index 45a7ea3656..100ada6691 100644 --- a/adapters/33across/33across.go +++ b/adapters/33across/33across.go @@ -7,11 +7,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type TtxAdapter struct { diff --git a/adapters/33across/33across_test.go b/adapters/33across/33across_test.go index 3ed177deac..87880b0d99 100644 --- a/adapters/33across/33across_test.go +++ b/adapters/33across/33across_test.go @@ -3,9 +3,9 @@ package ttx 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) { diff --git a/adapters/33across/params_test.go b/adapters/33across/params_test.go index 8517c5939a..dd05a28d77 100644 --- a/adapters/33across/params_test.go +++ b/adapters/33across/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" ) // This file actually intends to test static/bidder-params/33across.json diff --git a/adapters/aax/aax.go b/adapters/aax/aax.go index 1096955965..8dae76f39d 100644 --- a/adapters/aax/aax.go +++ b/adapters/aax/aax.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/aax/aax_test.go b/adapters/aax/aax_test.go index ad24a2d62e..d1adbcb39f 100644 --- a/adapters/aax/aax_test.go +++ b/adapters/aax/aax_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/aax/params_test.go b/adapters/aax/params_test.go index 0f93a063e6..8c652e2b4e 100644 --- a/adapters/aax/params_test.go +++ b/adapters/aax/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" ) // This file actually intends to test static/bidder-params/aax.json diff --git a/adapters/aceex/aceex.go b/adapters/aceex/aceex.go index 73a040bbe5..202eb442ba 100644 --- a/adapters/aceex/aceex.go +++ b/adapters/aceex/aceex.go @@ -7,12 +7,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/aceex/aceex_test.go b/adapters/aceex/aceex_test.go index 7aef7dd93f..afa2a81c96 100644 --- a/adapters/aceex/aceex_test.go +++ b/adapters/aceex/aceex_test.go @@ -3,9 +3,9 @@ package aceex 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/aceex/params_test.go b/adapters/aceex/params_test.go index c09e268307..72a4bb238f 100644 --- a/adapters/aceex/params_test.go +++ b/adapters/aceex/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" ) var validParams = []string{ diff --git a/adapters/acuityads/acuityads.go b/adapters/acuityads/acuityads.go index e05ded95e8..f9ae431b0b 100644 --- a/adapters/acuityads/acuityads.go +++ b/adapters/acuityads/acuityads.go @@ -7,12 +7,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 AcuityAdsAdapter struct { diff --git a/adapters/acuityads/acuityads_test.go b/adapters/acuityads/acuityads_test.go index b19abd3f7d..0997a6caff 100644 --- a/adapters/acuityads/acuityads_test.go +++ b/adapters/acuityads/acuityads_test.go @@ -3,9 +3,9 @@ package acuityads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/acuityads/params_test.go b/adapters/acuityads/params_test.go index 756dda3ea1..a1fe43f13b 100644 --- a/adapters/acuityads/params_test.go +++ b/adapters/acuityads/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" ) var validParams = []string{ diff --git a/adapters/adagio/adagio.go b/adapters/adagio/adagio.go index cf5819e978..1d3fd26a06 100644 --- a/adapters/adagio/adagio.go +++ b/adapters/adagio/adagio.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/adagio/adagio_test.go b/adapters/adagio/adagio_test.go index f006fe821d..ef4e28916f 100644 --- a/adapters/adagio/adagio_test.go +++ b/adapters/adagio/adagio_test.go @@ -3,9 +3,9 @@ package adagio 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) { diff --git a/adapters/adagio/params_test.go b/adapters/adagio/params_test.go index e7619b5298..7f974754ec 100644 --- a/adapters/adagio/params_test.go +++ b/adapters/adagio/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) { diff --git a/adapters/adapterstest/test_json.go b/adapters/adapterstest/test_json.go index 05312bf29b..911a5b408d 100644 --- a/adapters/adapterstest/test_json.go +++ b/adapters/adapterstest/test_json.go @@ -15,9 +15,9 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/mitchellh/copystructure" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/yudai/gojsondiff" "github.com/yudai/gojsondiff/formatter" diff --git a/adapters/adelement/adelement.go b/adapters/adelement/adelement.go index 11b79ad37b..18f9533e95 100644 --- a/adapters/adelement/adelement.go +++ b/adapters/adelement/adelement.go @@ -6,12 +6,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/adelement/adelement_test.go b/adapters/adelement/adelement_test.go index 2cfa599f80..77ee78196b 100644 --- a/adapters/adelement/adelement_test.go +++ b/adapters/adelement/adelement_test.go @@ -3,9 +3,9 @@ package adelement 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adf/adf.go b/adapters/adf/adf.go index 08fb9b8bb4..a75de8f291 100644 --- a/adapters/adf/adf.go +++ b/adapters/adf/adf.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/adf/adf_test.go b/adapters/adf/adf_test.go index 21e8a769c1..e362c600da 100644 --- a/adapters/adf/adf_test.go +++ b/adapters/adf/adf_test.go @@ -3,9 +3,9 @@ package adf 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) { diff --git a/adapters/adf/params_test.go b/adapters/adf/params_test.go index 9b3fd7b3e3..f3b4ebfdf5 100644 --- a/adapters/adf/params_test.go +++ b/adapters/adf/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" ) // This file actually intends to test static/bidder-params/adf.json diff --git a/adapters/adgeneration/adgeneration.go b/adapters/adgeneration/adgeneration.go index 31e27b862a..89492eb7e0 100644 --- a/adapters/adgeneration/adgeneration.go +++ b/adapters/adgeneration/adgeneration.go @@ -10,11 +10,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type AdgenerationAdapter struct { diff --git a/adapters/adgeneration/adgeneration_test.go b/adapters/adgeneration/adgeneration_test.go index e12ed431f0..14161750c7 100644 --- a/adapters/adgeneration/adgeneration_test.go +++ b/adapters/adgeneration/adgeneration_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adgeneration/params_test.go b/adapters/adgeneration/params_test.go index bdef4ec1d0..b343f079c5 100644 --- a/adapters/adgeneration/params_test.go +++ b/adapters/adgeneration/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) { diff --git a/adapters/adhese/adhese.go b/adapters/adhese/adhese.go index 9440a1f580..79bfaef404 100644 --- a/adapters/adhese/adhese.go +++ b/adapters/adhese/adhese.go @@ -5,12 +5,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/adhese/adhese_test.go b/adapters/adhese/adhese_test.go index 66ea75d865..3da9c74f2a 100644 --- a/adapters/adhese/adhese_test.go +++ b/adapters/adhese/adhese_test.go @@ -4,9 +4,9 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adhese/params_test.go b/adapters/adhese/params_test.go index b8ca161d57..ec0f2c5421 100644 --- a/adapters/adhese/params_test.go +++ b/adapters/adhese/params_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestValidParams(t *testing.T) { diff --git a/adapters/adkernel/adkernel.go b/adapters/adkernel/adkernel.go index 443da423fc..d8c6290274 100644 --- a/adapters/adkernel/adkernel.go +++ b/adapters/adkernel/adkernel.go @@ -9,12 +9,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" ) const ( diff --git a/adapters/adkernel/adkernel_test.go b/adapters/adkernel/adkernel_test.go index f874e92d57..8eb8e6bbfd 100644 --- a/adapters/adkernel/adkernel_test.go +++ b/adapters/adkernel/adkernel_test.go @@ -3,9 +3,9 @@ package adkernel 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adkernelAdn/adkernelAdn.go b/adapters/adkernelAdn/adkernelAdn.go index ffee88250c..e04d861858 100644 --- a/adapters/adkernelAdn/adkernelAdn.go +++ b/adapters/adkernelAdn/adkernelAdn.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 adkernelAdnAdapter struct { diff --git a/adapters/adkernelAdn/adkernelAdn_test.go b/adapters/adkernelAdn/adkernelAdn_test.go index f99da32940..269bea8395 100644 --- a/adapters/adkernelAdn/adkernelAdn_test.go +++ b/adapters/adkernelAdn/adkernelAdn_test.go @@ -3,9 +3,9 @@ package adkernelAdn 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adman/adman.go b/adapters/adman/adman.go index 8f90a0fe5b..818f38b2ab 100644 --- a/adapters/adman/adman.go +++ b/adapters/adman/adman.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // AdmanAdapter struct diff --git a/adapters/adman/adman_test.go b/adapters/adman/adman_test.go index 1a8eccca62..04a6cea0e0 100644 --- a/adapters/adman/adman_test.go +++ b/adapters/adman/adman_test.go @@ -3,9 +3,9 @@ package adman 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) { diff --git a/adapters/adman/params_test.go b/adapters/adman/params_test.go index 97b3d8f3f2..0beac5f516 100644 --- a/adapters/adman/params_test.go +++ b/adapters/adman/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" ) // TestValidParams makes sure that the adman schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/admatic/admatic.go b/adapters/admatic/admatic.go index 435eaba09e..e435a7b72a 100644 --- a/adapters/admatic/admatic.go +++ b/adapters/admatic/admatic.go @@ -7,12 +7,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/admatic/admatic_test.go b/adapters/admatic/admatic_test.go index c98f14e90a..26dd8090d5 100644 --- a/adapters/admatic/admatic_test.go +++ b/adapters/admatic/admatic_test.go @@ -3,9 +3,9 @@ package admatic 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/admatic/params_test.go b/adapters/admatic/params_test.go index fc92a1d779..4d656957f7 100644 --- a/adapters/admatic/params_test.go +++ b/adapters/admatic/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) { diff --git a/adapters/admixer/admixer.go b/adapters/admixer/admixer.go index 726c2cb98c..71765e5a79 100644 --- a/adapters/admixer/admixer.go +++ b/adapters/admixer/admixer.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type AdmixerAdapter struct { diff --git a/adapters/admixer/admixer_test.go b/adapters/admixer/admixer_test.go index 62615a63b3..d092fbfc49 100644 --- a/adapters/admixer/admixer_test.go +++ b/adapters/admixer/admixer_test.go @@ -3,9 +3,9 @@ package admixer 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) { diff --git a/adapters/admixer/params_test.go b/adapters/admixer/params_test.go index cdc8d56c77..687cceb1b9 100644 --- a/adapters/admixer/params_test.go +++ b/adapters/admixer/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" ) // This file actually intends to test static/bidder-params/admixer.json diff --git a/adapters/adnuntius/adnuntius.go b/adapters/adnuntius/adnuntius.go index c1a929a784..7b0f8f3831 100644 --- a/adapters/adnuntius/adnuntius.go +++ b/adapters/adnuntius/adnuntius.go @@ -10,12 +10,12 @@ import ( "github.com/buger/jsonparser" "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" - "github.com/prebid/prebid-server/v3/util/timeutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) const defaultNetwork = "default" diff --git a/adapters/adnuntius/adnuntius_test.go b/adapters/adnuntius/adnuntius_test.go index 8b048f7996..b2f78475eb 100644 --- a/adapters/adnuntius/adnuntius_test.go +++ b/adapters/adnuntius/adnuntius_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adnuntius/adnuntius_types.go b/adapters/adnuntius/adnuntius_types.go index e65a4ddb0b..f218a85e95 100644 --- a/adapters/adnuntius/adnuntius_types.go +++ b/adapters/adnuntius/adnuntius_types.go @@ -3,7 +3,7 @@ package adnuntius import ( "encoding/json" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) type QueryString map[string]string diff --git a/adapters/adnuntius/adnuntius_utils.go b/adapters/adnuntius/adnuntius_utils.go index 47e25bee6b..562a0a3bf1 100644 --- a/adapters/adnuntius/adnuntius_utils.go +++ b/adapters/adnuntius/adnuntius_utils.go @@ -8,8 +8,8 @@ import ( "strconv" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type RequestExt struct { diff --git a/adapters/adnuntius/params_test.go b/adapters/adnuntius/params_test.go index 92db0b9e5a..9ecae3ef5a 100644 --- a/adapters/adnuntius/params_test.go +++ b/adapters/adnuntius/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" ) // This file actually intends to test static/bidder-params/adnuntius.json diff --git a/adapters/adot/adot.go b/adapters/adot/adot.go index fc32ef6cae..d0c8d8dd92 100644 --- a/adapters/adot/adot.go +++ b/adapters/adot/adot.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/adot/adot_test.go b/adapters/adot/adot_test.go index d5d5afc6c4..f25379b8d3 100644 --- a/adapters/adot/adot_test.go +++ b/adapters/adot/adot_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adot/params_test.go b/adapters/adot/params_test.go index a64401e14a..2c2b4baa7a 100644 --- a/adapters/adot/params_test.go +++ b/adapters/adot/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" ) // This file actually intends to test static/bidder-params/adot.json diff --git a/adapters/adpone/adpone.go b/adapters/adpone/adpone.go index bdf7239889..944238767d 100644 --- a/adapters/adpone/adpone.go +++ b/adapters/adpone/adpone.go @@ -6,12 +6,12 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // Builder builds a new instance of the Adpone adapter for the given bidder with the given config. diff --git a/adapters/adpone/adpone_test.go b/adapters/adpone/adpone_test.go index e90055b2e6..418574cdcb 100644 --- a/adapters/adpone/adpone_test.go +++ b/adapters/adpone/adpone_test.go @@ -3,9 +3,9 @@ package adpone 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" ) const testsDir = "adponetest" diff --git a/adapters/adprime/adprime.go b/adapters/adprime/adprime.go index a4c041ae32..517ddca7a7 100644 --- a/adapters/adprime/adprime.go +++ b/adapters/adprime/adprime.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // AdprimeAdapter struct diff --git a/adapters/adprime/adprime_test.go b/adapters/adprime/adprime_test.go index 0b238b5bee..091c6ee7d2 100644 --- a/adapters/adprime/adprime_test.go +++ b/adapters/adprime/adprime_test.go @@ -3,9 +3,9 @@ package adprime 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) { diff --git a/adapters/adprime/params_test.go b/adapters/adprime/params_test.go index 18556d990e..ea05776e2a 100644 --- a/adapters/adprime/params_test.go +++ b/adapters/adprime/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" ) // TestValidParams makes sure that the adprime schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/adquery/adquery.go b/adapters/adquery/adquery.go index 4181370005..f730bc9cd7 100644 --- a/adapters/adquery/adquery.go +++ b/adapters/adquery/adquery.go @@ -9,11 +9,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/adquery/adquery_test.go b/adapters/adquery/adquery_test.go index 913e578195..d06f077729 100644 --- a/adapters/adquery/adquery_test.go +++ b/adapters/adquery/adquery_test.go @@ -3,9 +3,9 @@ package adquery 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) { diff --git a/adapters/adquery/params_test.go b/adapters/adquery/params_test.go index 5619f59cb5..b88b54d8a3 100644 --- a/adapters/adquery/params_test.go +++ b/adapters/adquery/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) { diff --git a/adapters/adquery/types.go b/adapters/adquery/types.go index 62692bb0d0..db173ed408 100644 --- a/adapters/adquery/types.go +++ b/adapters/adquery/types.go @@ -1,6 +1,6 @@ package adquery -import "github.com/prebid/prebid-server/v3/openrtb_ext" +import "github.com/prebid/prebid-server/v4/openrtb_ext" type BidderRequest struct { V string `json:"v"` diff --git a/adapters/adrino/adrino.go b/adapters/adrino/adrino.go index 9139d01789..545956383e 100644 --- a/adapters/adrino/adrino.go +++ b/adapters/adrino/adrino.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/adrino/adrino_test.go b/adapters/adrino/adrino_test.go index 48875bed7c..fe481dc7f9 100644 --- a/adapters/adrino/adrino_test.go +++ b/adapters/adrino/adrino_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/adrino/params_test.go b/adapters/adrino/params_test.go index a160113fbd..43d9ae9249 100644 --- a/adapters/adrino/params_test.go +++ b/adapters/adrino/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" ) // This file actually intends to test static/bidder-params/adrino.json diff --git a/adapters/adtarget/adtarget.go b/adapters/adtarget/adtarget.go index c78ffe830f..1e5820d639 100644 --- a/adapters/adtarget/adtarget.go +++ b/adapters/adtarget/adtarget.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type AdtargetAdapter struct { diff --git a/adapters/adtarget/adtarget_test.go b/adapters/adtarget/adtarget_test.go index 23cb51fdfa..57d9f74b96 100644 --- a/adapters/adtarget/adtarget_test.go +++ b/adapters/adtarget/adtarget_test.go @@ -3,9 +3,9 @@ package adtarget 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) { diff --git a/adapters/adtarget/params_test.go b/adapters/adtarget/params_test.go index cb5a8c9479..aace4e61ad 100644 --- a/adapters/adtarget/params_test.go +++ b/adapters/adtarget/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" ) // This file actually intends to test static/bidder-params/adtarget.json diff --git a/adapters/adtelligent/adtelligent.go b/adapters/adtelligent/adtelligent.go index f56a39736a..b10b35b2f2 100644 --- a/adapters/adtelligent/adtelligent.go +++ b/adapters/adtelligent/adtelligent.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type AdtelligentAdapter struct { diff --git a/adapters/adtelligent/adtelligent_test.go b/adapters/adtelligent/adtelligent_test.go index 64a4573ac1..5e3b8d163f 100644 --- a/adapters/adtelligent/adtelligent_test.go +++ b/adapters/adtelligent/adtelligent_test.go @@ -3,9 +3,9 @@ package adtelligent 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) { diff --git a/adapters/adtelligent/params_test.go b/adapters/adtelligent/params_test.go index bd3a2b8583..e9fc435525 100644 --- a/adapters/adtelligent/params_test.go +++ b/adapters/adtelligent/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" ) // This file actually intends to test static/bidder-params/adtelligent.json diff --git a/adapters/adtonos/adtonos.go b/adapters/adtonos/adtonos.go index e3c20cd932..a15918b99e 100644 --- a/adapters/adtonos/adtonos.go +++ b/adapters/adtonos/adtonos.go @@ -7,12 +7,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/adtonos/adtonos_test.go b/adapters/adtonos/adtonos_test.go index 683ce3e445..ff2709547c 100644 --- a/adapters/adtonos/adtonos_test.go +++ b/adapters/adtonos/adtonos_test.go @@ -3,9 +3,9 @@ package adtonos 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adtonos/params_test.go b/adapters/adtonos/params_test.go index 703446c9de..b3401fc88a 100644 --- a/adapters/adtonos/params_test.go +++ b/adapters/adtonos/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) { diff --git a/adapters/adtrgtme/adtrgtme.go b/adapters/adtrgtme/adtrgtme.go index a592cfc7c4..977a5a57ad 100644 --- a/adapters/adtrgtme/adtrgtme.go +++ b/adapters/adtrgtme/adtrgtme.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/adtrgtme/adtrgtme_test.go b/adapters/adtrgtme/adtrgtme_test.go index d57b5943af..6d9ae7f5a7 100644 --- a/adapters/adtrgtme/adtrgtme_test.go +++ b/adapters/adtrgtme/adtrgtme_test.go @@ -3,9 +3,9 @@ package adtrgtme 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) { diff --git a/adapters/adtrgtme/params_test.go b/adapters/adtrgtme/params_test.go index 19acaedc88..bedd06ba05 100644 --- a/adapters/adtrgtme/params_test.go +++ b/adapters/adtrgtme/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" ) var validParams = []string{ diff --git a/adapters/aduptech/aduptech.go b/adapters/aduptech/aduptech.go index dee3e679ef..574afe45fd 100644 --- a/adapters/aduptech/aduptech.go +++ b/adapters/aduptech/aduptech.go @@ -7,12 +7,12 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - prebidcurrency "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "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" + prebidcurrency "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "golang.org/x/text/currency" ) diff --git a/adapters/aduptech/aduptech_test.go b/adapters/aduptech/aduptech_test.go index 64dc6b3d41..26a59c0226 100644 --- a/adapters/aduptech/aduptech_test.go +++ b/adapters/aduptech/aduptech_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "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) { diff --git a/adapters/aduptech/params_test.go b/adapters/aduptech/params_test.go index ce0ae7d126..2899d0ee5f 100644 --- a/adapters/aduptech/params_test.go +++ b/adapters/aduptech/params_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) var validParams = []string{ diff --git a/adapters/advangelists/advangelists.go b/adapters/advangelists/advangelists.go index 1d4cd4fb64..677d46e0aa 100644 --- a/adapters/advangelists/advangelists.go +++ b/adapters/advangelists/advangelists.go @@ -7,12 +7,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 AdvangelistsAdapter struct { diff --git a/adapters/advangelists/advangelists_test.go b/adapters/advangelists/advangelists_test.go index 64ae4c89fa..bfebf98c68 100644 --- a/adapters/advangelists/advangelists_test.go +++ b/adapters/advangelists/advangelists_test.go @@ -3,9 +3,9 @@ package advangelists 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/advangelists/params_test.go b/adapters/advangelists/params_test.go index 8286f7f84a..349f8ea95e 100644 --- a/adapters/advangelists/params_test.go +++ b/adapters/advangelists/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) { diff --git a/adapters/adverxo/adverxo.go b/adapters/adverxo/adverxo.go index c76038ebde..f0f784d71b 100644 --- a/adapters/adverxo/adverxo.go +++ b/adapters/adverxo/adverxo.go @@ -11,11 +11,11 @@ import ( "github.com/buger/jsonparser" "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/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" ) type adapter struct { diff --git a/adapters/adverxo/adverxo_test.go b/adapters/adverxo/adverxo_test.go index ca32d50bc3..6194208dd7 100644 --- a/adapters/adverxo/adverxo_test.go +++ b/adapters/adverxo/adverxo_test.go @@ -3,9 +3,9 @@ package adverxo 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adverxo/params_test.go b/adapters/adverxo/params_test.go index a871a03c6e..f18aea3d94 100644 --- a/adapters/adverxo/params_test.go +++ b/adapters/adverxo/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) { diff --git a/adapters/adview/adview.go b/adapters/adview/adview.go index 55bf228450..8ea0009d53 100644 --- a/adapters/adview/adview.go +++ b/adapters/adview/adview.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/adview/adview_test.go b/adapters/adview/adview_test.go index 08e824a097..3d9b8a531b 100644 --- a/adapters/adview/adview_test.go +++ b/adapters/adview/adview_test.go @@ -3,9 +3,9 @@ package adview 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/adview/params_test.go b/adapters/adview/params_test.go index 9dd1c57c2a..748572f1c0 100644 --- a/adapters/adview/params_test.go +++ b/adapters/adview/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) { diff --git a/adapters/adxcg/adxcg.go b/adapters/adxcg/adxcg.go index 3b5e290ca3..355b685147 100644 --- a/adapters/adxcg/adxcg.go +++ b/adapters/adxcg/adxcg.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // Builder builds a new instance of the Adxcg adapter for the given bidder with the given config. diff --git a/adapters/adxcg/adxcg_test.go b/adapters/adxcg/adxcg_test.go index 0d94721392..3e21e82941 100644 --- a/adapters/adxcg/adxcg_test.go +++ b/adapters/adxcg/adxcg_test.go @@ -3,9 +3,9 @@ package adxcg 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" ) const testsDir = "adxcgtest" diff --git a/adapters/adyoulike/adyoulike.go b/adapters/adyoulike/adyoulike.go index dbc76f3f75..49118a8068 100644 --- a/adapters/adyoulike/adyoulike.go +++ b/adapters/adyoulike/adyoulike.go @@ -8,11 +8,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { diff --git a/adapters/adyoulike/adyoulike_test.go b/adapters/adyoulike/adyoulike_test.go index 5a6c91b1c8..80b4d8e9f4 100644 --- a/adapters/adyoulike/adyoulike_test.go +++ b/adapters/adyoulike/adyoulike_test.go @@ -3,9 +3,9 @@ package adyoulike 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" ) const testsBidderEndpoint = "https://localhost/bid/4" diff --git a/adapters/adyoulike/params_test.go b/adapters/adyoulike/params_test.go index 7c6630fbef..f76a9bf456 100644 --- a/adapters/adyoulike/params_test.go +++ b/adapters/adyoulike/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" ) // This file actually intends to test static/bidder-params/adyoulike.json diff --git a/adapters/afront/afront.go b/adapters/afront/afront.go index f9c41b6a1b..5d69bd0130 100644 --- a/adapters/afront/afront.go +++ b/adapters/afront/afront.go @@ -6,12 +6,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/afront/afront_test.go b/adapters/afront/afront_test.go index 8a2fde9523..2472f62968 100644 --- a/adapters/afront/afront_test.go +++ b/adapters/afront/afront_test.go @@ -3,9 +3,9 @@ package afront 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/afront/params_test.go b/adapters/afront/params_test.go index b50ff16425..252c8ce043 100644 --- a/adapters/afront/params_test.go +++ b/adapters/afront/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" ) var validParams = []string{ diff --git a/adapters/aidem/aidem.go b/adapters/aidem/aidem.go index 6e8a740959..7486e37981 100644 --- a/adapters/aidem/aidem.go +++ b/adapters/aidem/aidem.go @@ -7,12 +7,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/aidem/aidem_test.go b/adapters/aidem/aidem_test.go index 395bd2ca78..8224cb7a05 100644 --- a/adapters/aidem/aidem_test.go +++ b/adapters/aidem/aidem_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/aidem/params_test.go b/adapters/aidem/params_test.go index bea1d26e3d..933df84581 100644 --- a/adapters/aidem/params_test.go +++ b/adapters/aidem/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" ) // This file actually intends to test static/bidder-params/aidem.json TODO: MUST BE CREATED diff --git a/adapters/aja/aja.go b/adapters/aja/aja.go index 82007b02d0..2ed1306c7b 100644 --- a/adapters/aja/aja.go +++ b/adapters/aja/aja.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type AJAAdapter struct { diff --git a/adapters/aja/aja_test.go b/adapters/aja/aja_test.go index ab4165d09a..6de57ef680 100644 --- a/adapters/aja/aja_test.go +++ b/adapters/aja/aja_test.go @@ -3,9 +3,9 @@ package aja 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" ) const testsBidderEndpoint = "https://localhost/bid/4" diff --git a/adapters/akcelo/akcelo.go b/adapters/akcelo/akcelo.go index 4abb4c9ef9..78f99bca6c 100644 --- a/adapters/akcelo/akcelo.go +++ b/adapters/akcelo/akcelo.go @@ -5,12 +5,12 @@ import ( "fmt" "github.com/buger/jsonparser" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "net/http" "net/url" ) diff --git a/adapters/akcelo/akcelo_test.go b/adapters/akcelo/akcelo_test.go index a67a31efce..1b2cf90d6d 100644 --- a/adapters/akcelo/akcelo_test.go +++ b/adapters/akcelo/akcelo_test.go @@ -1,9 +1,9 @@ package akcelo import ( - "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" "github.com/stretchr/testify/require" "testing" ) diff --git a/adapters/akcelo/params_test.go b/adapters/akcelo/params_test.go index 0ff4d9e01f..2b61d9fbf2 100644 --- a/adapters/akcelo/params_test.go +++ b/adapters/akcelo/params_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestValidParams(t *testing.T) { diff --git a/adapters/algorix/algorix.go b/adapters/algorix/algorix.go index f6848e58e3..2e1ee250b1 100644 --- a/adapters/algorix/algorix.go +++ b/adapters/algorix/algorix.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/algorix/algorix_test.go b/adapters/algorix/algorix_test.go index 6b6d21e4d1..575e7fdef1 100644 --- a/adapters/algorix/algorix_test.go +++ b/adapters/algorix/algorix_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/algorix/params_test.go b/adapters/algorix/params_test.go index 6b5570c9ad..e5d48cfc3d 100644 --- a/adapters/algorix/params_test.go +++ b/adapters/algorix/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) { diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index c85b793315..a207c37ace 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -8,14 +8,14 @@ import ( "strconv" "strings" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/floors" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/floors" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const price_macro = "${AUCTION_PRICE}" diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 65f296a58e..292f2ea1e4 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -3,10 +3,10 @@ package alkimi import ( "testing" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/alkimi/params_test.go b/adapters/alkimi/params_test.go index 0ed0be05c6..0d92aab620 100644 --- a/adapters/alkimi/params_test.go +++ b/adapters/alkimi/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) { diff --git a/adapters/alliance_gravity/alliance_gravity.go b/adapters/alliance_gravity/alliance_gravity.go index a79a759140..73aec9b047 100644 --- a/adapters/alliance_gravity/alliance_gravity.go +++ b/adapters/alliance_gravity/alliance_gravity.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/alliance_gravity/alliance_gravity_test.go b/adapters/alliance_gravity/alliance_gravity_test.go index 1a5adcc64b..7378ec06d5 100644 --- a/adapters/alliance_gravity/alliance_gravity_test.go +++ b/adapters/alliance_gravity/alliance_gravity_test.go @@ -3,9 +3,9 @@ package alliance_gravity 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) { diff --git a/adapters/alliance_gravity/params_test.go b/adapters/alliance_gravity/params_test.go index c81fdf48e7..697c99a48f 100644 --- a/adapters/alliance_gravity/params_test.go +++ b/adapters/alliance_gravity/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) { diff --git a/adapters/amx/amx.go b/adapters/amx/amx.go index 38e0f4512e..e133b16cc2 100644 --- a/adapters/amx/amx.go +++ b/adapters/amx/amx.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const nbrHeaderName = "x-nbr" diff --git a/adapters/amx/amx_test.go b/adapters/amx/amx_test.go index 152fcf2b40..e1522a88a1 100644 --- a/adapters/amx/amx_test.go +++ b/adapters/amx/amx_test.go @@ -6,12 +6,12 @@ import ( "testing" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" ) const ( diff --git a/adapters/amx/params_test.go b/adapters/amx/params_test.go index e44f8a7bbf..9b6f56178d 100644 --- a/adapters/amx/params_test.go +++ b/adapters/amx/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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/apacdex/apacdex.go b/adapters/apacdex/apacdex.go index 698c204e25..fbcff9ee6d 100644 --- a/adapters/apacdex/apacdex.go +++ b/adapters/apacdex/apacdex.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/apacdex/apacdex_test.go b/adapters/apacdex/apacdex_test.go index 4e9e2f4b0e..3fde5068e5 100644 --- a/adapters/apacdex/apacdex_test.go +++ b/adapters/apacdex/apacdex_test.go @@ -3,9 +3,9 @@ package apacdex 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) { diff --git a/adapters/apacdex/params_test.go b/adapters/apacdex/params_test.go index ba680ea681..37140f7825 100644 --- a/adapters/apacdex/params_test.go +++ b/adapters/apacdex/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" ) // This file actually intends to test static/bidder-params/apacdex.json diff --git a/adapters/appnexus/appnexus.go b/adapters/appnexus/appnexus.go index a25f3f3164..457ffa642b 100644 --- a/adapters/appnexus/appnexus.go +++ b/adapters/appnexus/appnexus.go @@ -13,15 +13,15 @@ import ( "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/randomutil" - - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/randomutil" + + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/appnexus/appnexus_test.go b/adapters/appnexus/appnexus_test.go index 63973c6dc3..0772026190 100644 --- a/adapters/appnexus/appnexus_test.go +++ b/adapters/appnexus/appnexus_test.go @@ -4,9 +4,9 @@ import ( "net/url" "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/appnexus/params_test.go b/adapters/appnexus/params_test.go index 225b1ac323..6ac1ddc426 100644 --- a/adapters/appnexus/params_test.go +++ b/adapters/appnexus/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" ) // This file actually intends to test static/bidder-params/appnexus.json diff --git a/adapters/appush/appush.go b/adapters/appush/appush.go index c78e0b872c..f6fa89e100 100644 --- a/adapters/appush/appush.go +++ b/adapters/appush/appush.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/appush/appush_test.go b/adapters/appush/appush_test.go index 1fe49f87d1..d0c8799436 100644 --- a/adapters/appush/appush_test.go +++ b/adapters/appush/appush_test.go @@ -3,9 +3,9 @@ package appush 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) { diff --git a/adapters/appush/params_test.go b/adapters/appush/params_test.go index b877eb7bfd..21809cd04b 100644 --- a/adapters/appush/params_test.go +++ b/adapters/appush/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) { diff --git a/adapters/aso/aso.go b/adapters/aso/aso.go index 6df776949a..c73616bc91 100644 --- a/adapters/aso/aso.go +++ b/adapters/aso/aso.go @@ -9,12 +9,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/aso/aso_test.go b/adapters/aso/aso_test.go index 41d8e65048..c18ac4efbb 100644 --- a/adapters/aso/aso_test.go +++ b/adapters/aso/aso_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/aso/params_test.go b/adapters/aso/params_test.go index 4d303220d1..71ba371f54 100644 --- a/adapters/aso/params_test.go +++ b/adapters/aso/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) { diff --git a/adapters/audienceNetwork/facebook.go b/adapters/audienceNetwork/facebook.go index dc4042412d..acf618ecb2 100644 --- a/adapters/audienceNetwork/facebook.go +++ b/adapters/audienceNetwork/facebook.go @@ -13,13 +13,13 @@ import ( "github.com/buger/jsonparser" "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" - "github.com/prebid/prebid-server/v3/util/maputil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/maputil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) var supportedBannerHeights = map[int64]struct{}{ diff --git a/adapters/audienceNetwork/facebook_test.go b/adapters/audienceNetwork/facebook_test.go index 6fdc121f94..a9740bb57c 100644 --- a/adapters/audienceNetwork/facebook_test.go +++ b/adapters/audienceNetwork/facebook_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/automatad/automatad.go b/adapters/automatad/automatad.go index cfe5f5089b..6ce0602fb7 100644 --- a/adapters/automatad/automatad.go +++ b/adapters/automatad/automatad.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/automatad/automatad_test.go b/adapters/automatad/automatad_test.go index 515025c862..faa3431e8e 100644 --- a/adapters/automatad/automatad_test.go +++ b/adapters/automatad/automatad_test.go @@ -3,9 +3,9 @@ package automatad 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) { diff --git a/adapters/automatad/params_test.go b/adapters/automatad/params_test.go index 7f8d6e789e..ec3a42e5fd 100644 --- a/adapters/automatad/params_test.go +++ b/adapters/automatad/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) { diff --git a/adapters/avocet/avocet.go b/adapters/avocet/avocet.go index 8bf2b7d89a..a18bc4ed9e 100644 --- a/adapters/avocet/avocet.go +++ b/adapters/avocet/avocet.go @@ -7,11 +7,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // AvocetAdapter implements a adapters.Bidder compatible with the Avocet advertising platform. diff --git a/adapters/avocet/avocet_test.go b/adapters/avocet/avocet_test.go index 082a7c1ee6..42a417acaa 100644 --- a/adapters/avocet/avocet_test.go +++ b/adapters/avocet/avocet_test.go @@ -8,11 +8,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "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/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/axis/axis.go b/adapters/axis/axis.go index d28eca6a8a..3f104c75e7 100644 --- a/adapters/axis/axis.go +++ b/adapters/axis/axis.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/axis/axis_test.go b/adapters/axis/axis_test.go index 24048f1856..42481f0e40 100644 --- a/adapters/axis/axis_test.go +++ b/adapters/axis/axis_test.go @@ -3,9 +3,9 @@ package axis 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) { diff --git a/adapters/axis/params_test.go b/adapters/axis/params_test.go index ad5cec52fd..aa5b82f5d9 100644 --- a/adapters/axis/params_test.go +++ b/adapters/axis/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) { diff --git a/adapters/axonix/axonix.go b/adapters/axonix/axonix.go index 81e5937a14..33b19e14f8 100644 --- a/adapters/axonix/axonix.go +++ b/adapters/axonix/axonix.go @@ -10,12 +10,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/axonix/axonix_test.go b/adapters/axonix/axonix_test.go index 1d398c5351..73ac0d981d 100644 --- a/adapters/axonix/axonix_test.go +++ b/adapters/axonix/axonix_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/axonix/params_test.go b/adapters/axonix/params_test.go index b839bcb20f..645a72338d 100644 --- a/adapters/axonix/params_test.go +++ b/adapters/axonix/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" ) // This file actually intends to test static/bidder-params/axonix.json diff --git a/adapters/beachfront/beachfront.go b/adapters/beachfront/beachfront.go index 8e293837f1..869451c98e 100644 --- a/adapters/beachfront/beachfront.go +++ b/adapters/beachfront/beachfront.go @@ -10,12 +10,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const Seat = "beachfront" diff --git a/adapters/beachfront/beachfront_test.go b/adapters/beachfront/beachfront_test.go index 304747503f..b2beadce3f 100644 --- a/adapters/beachfront/beachfront_test.go +++ b/adapters/beachfront/beachfront_test.go @@ -3,9 +3,9 @@ package beachfront 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/beachfront/params_test.go b/adapters/beachfront/params_test.go index 3bfbeba635..13e341b5b7 100644 --- a/adapters/beachfront/params_test.go +++ b/adapters/beachfront/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) { diff --git a/adapters/beintoo/beintoo.go b/adapters/beintoo/beintoo.go index 18290e6df4..a76d57966c 100644 --- a/adapters/beintoo/beintoo.go +++ b/adapters/beintoo/beintoo.go @@ -8,11 +8,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type BeintooAdapter struct { diff --git a/adapters/beintoo/beintoo_test.go b/adapters/beintoo/beintoo_test.go index 8dfb257b3d..d6ca33bf19 100644 --- a/adapters/beintoo/beintoo_test.go +++ b/adapters/beintoo/beintoo_test.go @@ -3,9 +3,9 @@ package beintoo 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) { diff --git a/adapters/beintoo/params_test.go b/adapters/beintoo/params_test.go index 211912a8cb..f9c4e8f344 100644 --- a/adapters/beintoo/params_test.go +++ b/adapters/beintoo/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) { diff --git a/adapters/bematterfull/bematterfull.go b/adapters/bematterfull/bematterfull.go index 89b984c5eb..3c9c16d6b3 100644 --- a/adapters/bematterfull/bematterfull.go +++ b/adapters/bematterfull/bematterfull.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/bematterfull/bematterfulltest_test.go b/adapters/bematterfull/bematterfulltest_test.go index 92296231b0..9789cccae0 100644 --- a/adapters/bematterfull/bematterfulltest_test.go +++ b/adapters/bematterfull/bematterfulltest_test.go @@ -3,9 +3,9 @@ package bematterfull 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/bematterfull/params_test.go b/adapters/bematterfull/params_test.go index 769195f6f0..bd7478c4e5 100644 --- a/adapters/bematterfull/params_test.go +++ b/adapters/bematterfull/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" ) var validParams = []string{ diff --git a/adapters/beop/beop.go b/adapters/beop/beop.go index ffbb4c94bd..bb4f862a5d 100644 --- a/adapters/beop/beop.go +++ b/adapters/beop/beop.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/beop/beop_test.go b/adapters/beop/beop_test.go index 5960bc09f1..4be3022496 100644 --- a/adapters/beop/beop_test.go +++ b/adapters/beop/beop_test.go @@ -3,9 +3,9 @@ package beop import ( "testing" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "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) { diff --git a/adapters/beop/params_test.go b/adapters/beop/params_test.go index 5b854bd3af..63ba18c9b0 100644 --- a/adapters/beop/params_test.go +++ b/adapters/beop/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) { diff --git a/adapters/between/between.go b/adapters/between/between.go index fe20978285..6cbb88ca16 100644 --- a/adapters/between/between.go +++ b/adapters/between/between.go @@ -9,12 +9,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 BetweenAdapter struct { diff --git a/adapters/between/between_test.go b/adapters/between/between_test.go index 61f759126b..1a33e77102 100644 --- a/adapters/between/between_test.go +++ b/adapters/between/between_test.go @@ -3,9 +3,9 @@ package between 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/between/params_test.go b/adapters/between/params_test.go index 5e30dba116..7d16056f55 100644 --- a/adapters/between/params_test.go +++ b/adapters/between/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" ) // This file actually intends to test static/bidder-params/between.json diff --git a/adapters/beyondmedia/beyondmedia.go b/adapters/beyondmedia/beyondmedia.go index bafa5791d8..4e026aa0f4 100644 --- a/adapters/beyondmedia/beyondmedia.go +++ b/adapters/beyondmedia/beyondmedia.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/beyondmedia/beyondmedia_test.go b/adapters/beyondmedia/beyondmedia_test.go index 94eb5bd741..6050f70488 100644 --- a/adapters/beyondmedia/beyondmedia_test.go +++ b/adapters/beyondmedia/beyondmedia_test.go @@ -3,9 +3,9 @@ package beyondmedia 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) { diff --git a/adapters/beyondmedia/params_test.go b/adapters/beyondmedia/params_test.go index 2f6d969f1a..9804f12bde 100644 --- a/adapters/beyondmedia/params_test.go +++ b/adapters/beyondmedia/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) { diff --git a/adapters/bidder.go b/adapters/bidder.go index fb0ec07e03..0be99b0080 100644 --- a/adapters/bidder.go +++ b/adapters/bidder.go @@ -6,10 +6,10 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Bidder describes how to connect to external demand. diff --git a/adapters/bidmachine/bidmachine.go b/adapters/bidmachine/bidmachine.go index 81a72cdac5..b56fff83dc 100644 --- a/adapters/bidmachine/bidmachine.go +++ b/adapters/bidmachine/bidmachine.go @@ -12,12 +12,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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/bidmachine/bidmachine_test.go b/adapters/bidmachine/bidmachine_test.go index dc26633c4f..f303e49cde 100644 --- a/adapters/bidmachine/bidmachine_test.go +++ b/adapters/bidmachine/bidmachine_test.go @@ -3,9 +3,9 @@ package bidmachine 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/bidmachine/params_test.go b/adapters/bidmachine/params_test.go index 319fef8902..56d796c27c 100644 --- a/adapters/bidmachine/params_test.go +++ b/adapters/bidmachine/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) { diff --git a/adapters/bidmatic/bidmatic.go b/adapters/bidmatic/bidmatic.go index 32b7a2ee88..06678021dc 100644 --- a/adapters/bidmatic/bidmatic.go +++ b/adapters/bidmatic/bidmatic.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bidmatic/bidmatic_test.go b/adapters/bidmatic/bidmatic_test.go index b546eca545..f803c898ad 100644 --- a/adapters/bidmatic/bidmatic_test.go +++ b/adapters/bidmatic/bidmatic_test.go @@ -3,9 +3,9 @@ package bidmatic 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) { diff --git a/adapters/bidmatic/params_test.go b/adapters/bidmatic/params_test.go index bfea9fddae..cc13f7b979 100644 --- a/adapters/bidmatic/params_test.go +++ b/adapters/bidmatic/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" ) // This file actually intends to test static/bidder-params/bidmatic.json diff --git a/adapters/bidmyadz/bidmyadz.go b/adapters/bidmyadz/bidmyadz.go index b2f8cda564..87c92eb3bb 100644 --- a/adapters/bidmyadz/bidmyadz.go +++ b/adapters/bidmyadz/bidmyadz.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bidmyadz/bidmyadz_test.go b/adapters/bidmyadz/bidmyadz_test.go index f01af44cff..53b4bcc592 100644 --- a/adapters/bidmyadz/bidmyadz_test.go +++ b/adapters/bidmyadz/bidmyadz_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/bidmyadz/params_test.go b/adapters/bidmyadz/params_test.go index fca34b1024..e8a50bd7ee 100644 --- a/adapters/bidmyadz/params_test.go +++ b/adapters/bidmyadz/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" ) var validParams = []string{ diff --git a/adapters/bidscube/bidscube.go b/adapters/bidscube/bidscube.go index 8ccd794f86..2bb9dc25c7 100644 --- a/adapters/bidscube/bidscube.go +++ b/adapters/bidscube/bidscube.go @@ -9,11 +9,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bidscube/bidscube_test.go b/adapters/bidscube/bidscube_test.go index 5396ccd426..aec8219b84 100644 --- a/adapters/bidscube/bidscube_test.go +++ b/adapters/bidscube/bidscube_test.go @@ -3,9 +3,9 @@ package bidscube 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) { diff --git a/adapters/bidscube/params_test.go b/adapters/bidscube/params_test.go index 9f368f939a..00bc51dd1e 100644 --- a/adapters/bidscube/params_test.go +++ b/adapters/bidscube/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" ) // TestValidParams makes sure that the bidscube schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/bidstack/bidstack.go b/adapters/bidstack/bidstack.go index 555abff0c7..5172db1bb8 100644 --- a/adapters/bidstack/bidstack.go +++ b/adapters/bidstack/bidstack.go @@ -9,10 +9,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/bidstack/bidstack_test.go b/adapters/bidstack/bidstack_test.go index 9010ce5014..14d506497b 100644 --- a/adapters/bidstack/bidstack_test.go +++ b/adapters/bidstack/bidstack_test.go @@ -7,9 +7,9 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/bidstack/params_test.go b/adapters/bidstack/params_test.go index 3cca0f447b..cc24029280 100644 --- a/adapters/bidstack/params_test.go +++ b/adapters/bidstack/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" ) var validParams = []string{ diff --git a/adapters/bidtheatre/bidtheatre.go b/adapters/bidtheatre/bidtheatre.go index 8d3b149c7e..6e56171b2d 100644 --- a/adapters/bidtheatre/bidtheatre.go +++ b/adapters/bidtheatre/bidtheatre.go @@ -6,11 +6,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bidtheatre/bidtheatre_test.go b/adapters/bidtheatre/bidtheatre_test.go index 8a4daf5fbe..ca78a03f27 100644 --- a/adapters/bidtheatre/bidtheatre_test.go +++ b/adapters/bidtheatre/bidtheatre_test.go @@ -2,9 +2,9 @@ package bidtheatre import ( "github.com/prebid/openrtb/v20/openrtb2" - "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" "strings" "testing" ) diff --git a/adapters/bidtheatre/params_test.go b/adapters/bidtheatre/params_test.go index 64870afcba..51caec5f94 100644 --- a/adapters/bidtheatre/params_test.go +++ b/adapters/bidtheatre/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) { diff --git a/adapters/bigoad/bigoad.go b/adapters/bigoad/bigoad.go index e968139d59..7e4edd51fc 100644 --- a/adapters/bigoad/bigoad.go +++ b/adapters/bigoad/bigoad.go @@ -7,12 +7,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/bigoad/bigoad_test.go b/adapters/bigoad/bigoad_test.go index 7c51c8f80d..a171d66dc9 100644 --- a/adapters/bigoad/bigoad_test.go +++ b/adapters/bigoad/bigoad_test.go @@ -3,9 +3,9 @@ package bigoad 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/bigoad/param_test.go b/adapters/bigoad/param_test.go index 772bcb7721..9f456f65df 100644 --- a/adapters/bigoad/param_test.go +++ b/adapters/bigoad/param_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) { diff --git a/adapters/blasto/blasto.go b/adapters/blasto/blasto.go index e9917d0885..c02c4a1ce7 100644 --- a/adapters/blasto/blasto.go +++ b/adapters/blasto/blasto.go @@ -7,12 +7,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/blasto/blasto_test.go b/adapters/blasto/blasto_test.go index 9b09c19ae6..4bce53bcde 100644 --- a/adapters/blasto/blasto_test.go +++ b/adapters/blasto/blasto_test.go @@ -3,9 +3,9 @@ package blasto 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/blasto/params_test.go b/adapters/blasto/params_test.go index c23f162d03..762b51185d 100644 --- a/adapters/blasto/params_test.go +++ b/adapters/blasto/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" ) var validParams = []string{ diff --git a/adapters/bliink/bliink.go b/adapters/bliink/bliink.go index 900c1de7ee..d5ce144c8c 100644 --- a/adapters/bliink/bliink.go +++ b/adapters/bliink/bliink.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bliink/bliink_test.go b/adapters/bliink/bliink_test.go index d5fa3aa58e..404f90127b 100644 --- a/adapters/bliink/bliink_test.go +++ b/adapters/bliink/bliink_test.go @@ -3,9 +3,9 @@ package bliink 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) { diff --git a/adapters/bliink/params_test.go b/adapters/bliink/params_test.go index 646ab96e4c..8b3620e962 100644 --- a/adapters/bliink/params_test.go +++ b/adapters/bliink/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" ) var validParams = []string{ diff --git a/adapters/blis/blis.go b/adapters/blis/blis.go index ed701a2241..617c6b82e6 100644 --- a/adapters/blis/blis.go +++ b/adapters/blis/blis.go @@ -8,13 +8,13 @@ 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/iterutil" - "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/iterutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/blis/blis_test.go b/adapters/blis/blis_test.go index b9fcc9836a..7ae808d8e8 100644 --- a/adapters/blis/blis_test.go +++ b/adapters/blis/blis_test.go @@ -4,9 +4,9 @@ import ( "github.com/stretchr/testify/assert" "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" "github.com/stretchr/testify/require" ) diff --git a/adapters/blis/params_test.go b/adapters/blis/params_test.go index 2a62836a06..b1535e8844 100644 --- a/adapters/blis/params_test.go +++ b/adapters/blis/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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/blue/blue.go b/adapters/blue/blue.go index 08b5167dd0..6f9537507f 100644 --- a/adapters/blue/blue.go +++ b/adapters/blue/blue.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/blue/blue_test.go b/adapters/blue/blue_test.go index 696d855d6a..815cbaf561 100644 --- a/adapters/blue/blue_test.go +++ b/adapters/blue/blue_test.go @@ -3,9 +3,9 @@ package blue 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 TestBidderBlue(t *testing.T) { diff --git a/adapters/blue/params_test.go b/adapters/blue/params_test.go index 27b1e02ea8..aac600299c 100644 --- a/adapters/blue/params_test.go +++ b/adapters/blue/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) { diff --git a/adapters/bluesea/bluesea.go b/adapters/bluesea/bluesea.go index 0428b22b6c..835f98c48e 100644 --- a/adapters/bluesea/bluesea.go +++ b/adapters/bluesea/bluesea.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bluesea/bluesea_test.go b/adapters/bluesea/bluesea_test.go index 2d0b5bdaca..df4ed7d6ec 100644 --- a/adapters/bluesea/bluesea_test.go +++ b/adapters/bluesea/bluesea_test.go @@ -3,9 +3,9 @@ package bluesea 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) { diff --git a/adapters/bluesea/params_test.go b/adapters/bluesea/params_test.go index 79d15d0baa..f9f7ee5b90 100644 --- a/adapters/bluesea/params_test.go +++ b/adapters/bluesea/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" ) // TestValidParams makes sure that the bluesea schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/bmtm/brightmountainmedia.go b/adapters/bmtm/brightmountainmedia.go index 6f48df6d4d..f1c8fd9719 100644 --- a/adapters/bmtm/brightmountainmedia.go +++ b/adapters/bmtm/brightmountainmedia.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/bmtm/brightmountainmedia_test.go b/adapters/bmtm/brightmountainmedia_test.go index 28af575c57..51ec50e6cd 100644 --- a/adapters/bmtm/brightmountainmedia_test.go +++ b/adapters/bmtm/brightmountainmedia_test.go @@ -3,9 +3,9 @@ package bmtm 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) { diff --git a/adapters/bmtm/params_test.go b/adapters/bmtm/params_test.go index f6f8b6105e..a2ff1104c0 100644 --- a/adapters/bmtm/params_test.go +++ b/adapters/bmtm/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) { diff --git a/adapters/boldwin/boldwin.go b/adapters/boldwin/boldwin.go index 2dbb145428..52f545086e 100644 --- a/adapters/boldwin/boldwin.go +++ b/adapters/boldwin/boldwin.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/boldwin/boldwin_test.go b/adapters/boldwin/boldwin_test.go index 1a270fcfe9..a6d3e3238e 100644 --- a/adapters/boldwin/boldwin_test.go +++ b/adapters/boldwin/boldwin_test.go @@ -3,9 +3,9 @@ package boldwin 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) { diff --git a/adapters/boldwin/params_test.go b/adapters/boldwin/params_test.go index 627af2418f..b122376848 100644 --- a/adapters/boldwin/params_test.go +++ b/adapters/boldwin/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) { diff --git a/adapters/boldwin_rapid/boldwin_rapid.go b/adapters/boldwin_rapid/boldwin_rapid.go index 1904cd8aca..62d2131fea 100644 --- a/adapters/boldwin_rapid/boldwin_rapid.go +++ b/adapters/boldwin_rapid/boldwin_rapid.go @@ -8,11 +8,11 @@ import ( "net/http" "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/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/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/boldwin_rapid/boldwin_rapid_test.go b/adapters/boldwin_rapid/boldwin_rapid_test.go index 58e03ca2aa..da55e420ae 100644 --- a/adapters/boldwin_rapid/boldwin_rapid_test.go +++ b/adapters/boldwin_rapid/boldwin_rapid_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/boldwin_rapid/params_test.go b/adapters/boldwin_rapid/params_test.go index d43843271a..eef731350d 100644 --- a/adapters/boldwin_rapid/params_test.go +++ b/adapters/boldwin_rapid/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) { diff --git a/adapters/brave/brave.go b/adapters/brave/brave.go index 4cca024f43..595df0ea0d 100755 --- a/adapters/brave/brave.go +++ b/adapters/brave/brave.go @@ -7,12 +7,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/brave/brave_test.go b/adapters/brave/brave_test.go index a1ea0cd70d..aceebd3a56 100644 --- a/adapters/brave/brave_test.go +++ b/adapters/brave/brave_test.go @@ -3,9 +3,9 @@ package brave 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/brave/params_test.go b/adapters/brave/params_test.go index fd0a6f8c63..06ec9f5f55 100644 --- a/adapters/brave/params_test.go +++ b/adapters/brave/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) { diff --git a/adapters/bwx/bwx.go b/adapters/bwx/bwx.go index 55e64a05c2..22b9451934 100644 --- a/adapters/bwx/bwx.go +++ b/adapters/bwx/bwx.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/bwx/bwx_test.go b/adapters/bwx/bwx_test.go index 10246ee8a8..edd87acf62 100644 --- a/adapters/bwx/bwx_test.go +++ b/adapters/bwx/bwx_test.go @@ -3,9 +3,9 @@ package bwx 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/bwx/params_test.go b/adapters/bwx/params_test.go index 515fbd5073..cd5d969bbf 100644 --- a/adapters/bwx/params_test.go +++ b/adapters/bwx/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" ) var validParams = []string{ diff --git a/adapters/cadent_aperture_mx/cadentaperturemx.go b/adapters/cadent_aperture_mx/cadentaperturemx.go index 58902bad55..9d62c1a5e6 100644 --- a/adapters/cadent_aperture_mx/cadentaperturemx.go +++ b/adapters/cadent_aperture_mx/cadentaperturemx.go @@ -11,11 +11,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/cadent_aperture_mx/cadentaperturemx_test.go b/adapters/cadent_aperture_mx/cadentaperturemx_test.go index 7a951555d0..a17eac4b66 100644 --- a/adapters/cadent_aperture_mx/cadentaperturemx_test.go +++ b/adapters/cadent_aperture_mx/cadentaperturemx_test.go @@ -3,10 +3,10 @@ package cadentaperturemx import ( "testing" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "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) { diff --git a/adapters/cadent_aperture_mx/params_test.go b/adapters/cadent_aperture_mx/params_test.go index d505bd8329..8fc1377c6a 100644 --- a/adapters/cadent_aperture_mx/params_test.go +++ b/adapters/cadent_aperture_mx/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) { diff --git a/adapters/ccx/ccx.go b/adapters/ccx/ccx.go index 64bb599afd..7685e624a6 100644 --- a/adapters/ccx/ccx.go +++ b/adapters/ccx/ccx.go @@ -6,12 +6,12 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/ccx/ccx_test.go b/adapters/ccx/ccx_test.go index de095d7259..3c68e9ccc0 100644 --- a/adapters/ccx/ccx_test.go +++ b/adapters/ccx/ccx_test.go @@ -3,9 +3,9 @@ package ccx 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) { diff --git a/adapters/ccx/params_test.go b/adapters/ccx/params_test.go index ff600fada1..2d296bc883 100644 --- a/adapters/ccx/params_test.go +++ b/adapters/ccx/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) { diff --git a/adapters/clydo/clydo.go b/adapters/clydo/clydo.go index 0b06bd74d8..967aab5682 100644 --- a/adapters/clydo/clydo.go +++ b/adapters/clydo/clydo.go @@ -6,12 +6,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/clydo/clydo_test.go b/adapters/clydo/clydo_test.go index ef21d1e486..c381fc6adc 100644 --- a/adapters/clydo/clydo_test.go +++ b/adapters/clydo/clydo_test.go @@ -3,9 +3,9 @@ package clydo 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/clydo/params_test.go b/adapters/clydo/params_test.go index 779c7eeadd..f3172f83b7 100644 --- a/adapters/clydo/params_test.go +++ b/adapters/clydo/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) { diff --git a/adapters/cointraffic/cointraffic.go b/adapters/cointraffic/cointraffic.go index 781d8def81..d5aff00551 100644 --- a/adapters/cointraffic/cointraffic.go +++ b/adapters/cointraffic/cointraffic.go @@ -5,10 +5,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/cointraffic/cointraffic_test.go b/adapters/cointraffic/cointraffic_test.go index 133dfd2af2..c73d8d6b3a 100644 --- a/adapters/cointraffic/cointraffic_test.go +++ b/adapters/cointraffic/cointraffic_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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" ) const testsDir = "cointraffictest" diff --git a/adapters/cointraffic/params_test.go b/adapters/cointraffic/params_test.go index 484a72c66b..3d0044d94b 100644 --- a/adapters/cointraffic/params_test.go +++ b/adapters/cointraffic/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" ) // This file actually intends to test static/bidder-params/cointraffic.json diff --git a/adapters/coinzilla/coinzilla.go b/adapters/coinzilla/coinzilla.go index 21e321406c..eeec012a34 100644 --- a/adapters/coinzilla/coinzilla.go +++ b/adapters/coinzilla/coinzilla.go @@ -6,12 +6,12 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { diff --git a/adapters/coinzilla/coinzilla_test.go b/adapters/coinzilla/coinzilla_test.go index 830028f24f..fff81adf18 100644 --- a/adapters/coinzilla/coinzilla_test.go +++ b/adapters/coinzilla/coinzilla_test.go @@ -3,9 +3,9 @@ package coinzilla 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" ) const testsDir = "coinzillatest" diff --git a/adapters/coinzilla/params_test.go b/adapters/coinzilla/params_test.go index d174b1441a..61586a8910 100644 --- a/adapters/coinzilla/params_test.go +++ b/adapters/coinzilla/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) { diff --git a/adapters/colossus/colossus.go b/adapters/colossus/colossus.go index 0fc1e50a29..5f3b2d1c7b 100644 --- a/adapters/colossus/colossus.go +++ b/adapters/colossus/colossus.go @@ -7,11 +7,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type ColossusAdapter struct { diff --git a/adapters/colossus/colossus_test.go b/adapters/colossus/colossus_test.go index 227bd635ae..903cd2ec65 100644 --- a/adapters/colossus/colossus_test.go +++ b/adapters/colossus/colossus_test.go @@ -3,9 +3,9 @@ package colossus 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) { diff --git a/adapters/colossus/params_test.go b/adapters/colossus/params_test.go index bf924e4eae..d4e80e4679 100644 --- a/adapters/colossus/params_test.go +++ b/adapters/colossus/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" ) // TestValidParams makes sure that the colossus schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/compass/compass.go b/adapters/compass/compass.go index 28f46bc7e2..0ab775a513 100644 --- a/adapters/compass/compass.go +++ b/adapters/compass/compass.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/compass/compass_test.go b/adapters/compass/compass_test.go index 7aed7616de..9e043d1c60 100644 --- a/adapters/compass/compass_test.go +++ b/adapters/compass/compass_test.go @@ -3,9 +3,9 @@ package compass 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) { diff --git a/adapters/compass/params_test.go b/adapters/compass/params_test.go index edabac2975..6de87dfe03 100644 --- a/adapters/compass/params_test.go +++ b/adapters/compass/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) { diff --git a/adapters/concert/concert.go b/adapters/concert/concert.go index adf7144274..5ac3269006 100644 --- a/adapters/concert/concert.go +++ b/adapters/concert/concert.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/concert/concert_test.go b/adapters/concert/concert_test.go index d6cea80fb9..397043b3da 100644 --- a/adapters/concert/concert_test.go +++ b/adapters/concert/concert_test.go @@ -3,9 +3,9 @@ package concert 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) { diff --git a/adapters/concert/params_test.go b/adapters/concert/params_test.go index b8ec65bda8..512f016482 100644 --- a/adapters/concert/params_test.go +++ b/adapters/concert/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) { diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index c479a2892f..fbd1af35e9 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -9,11 +9,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/connatix/connatix_test.go b/adapters/connatix/connatix_test.go index 018926ef25..fdaa76beef 100644 --- a/adapters/connatix/connatix_test.go +++ b/adapters/connatix/connatix_test.go @@ -3,9 +3,9 @@ package connatix 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) { diff --git a/adapters/connatix/models.go b/adapters/connatix/models.go index aebd51d097..3462829eae 100644 --- a/adapters/connatix/models.go +++ b/adapters/connatix/models.go @@ -1,7 +1,7 @@ package connatix import ( - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type adapter struct { diff --git a/adapters/connatix/params_test.go b/adapters/connatix/params_test.go index 254f660c1b..beb681aa7c 100644 --- a/adapters/connatix/params_test.go +++ b/adapters/connatix/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" ) // This file actually intends to test static/bidder-params/connatix.json diff --git a/adapters/connectad/connectad.go b/adapters/connectad/connectad.go index dd13bc3764..146e583eaf 100644 --- a/adapters/connectad/connectad.go +++ b/adapters/connectad/connectad.go @@ -8,11 +8,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type ConnectAdAdapter struct { diff --git a/adapters/connectad/connectad_test.go b/adapters/connectad/connectad_test.go index 4563e0045f..ac876a7a67 100644 --- a/adapters/connectad/connectad_test.go +++ b/adapters/connectad/connectad_test.go @@ -3,9 +3,9 @@ package connectad 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) { diff --git a/adapters/connectad/params_test.go b/adapters/connectad/params_test.go index dc7c40be72..12dd9c7be9 100644 --- a/adapters/connectad/params_test.go +++ b/adapters/connectad/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) { diff --git a/adapters/consumable/consumable.go b/adapters/consumable/consumable.go index 9b80fb1459..47d1ba3ea0 100644 --- a/adapters/consumable/consumable.go +++ b/adapters/consumable/consumable.go @@ -5,11 +5,11 @@ import ( "fmt" "net/http" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/consumable/consumable_test.go b/adapters/consumable/consumable_test.go index 200d6159ea..76a28d40d1 100644 --- a/adapters/consumable/consumable_test.go +++ b/adapters/consumable/consumable_test.go @@ -6,11 +6,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/consumable/params_test.go b/adapters/consumable/params_test.go index 3820acc737..6584982d81 100644 --- a/adapters/consumable/params_test.go +++ b/adapters/consumable/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" ) // This file actually intends to test static/bidder-params/consumable.json diff --git a/adapters/contxtful/contxtful.go b/adapters/contxtful/contxtful.go index 3dd8b5b2b9..3513579ffe 100644 --- a/adapters/contxtful/contxtful.go +++ b/adapters/contxtful/contxtful.go @@ -6,12 +6,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" ) // ContxtfulRequestPayload represents the complete request payload structure diff --git a/adapters/contxtful/contxtful_relay_test.go b/adapters/contxtful/contxtful_relay_test.go index 61f9773ab5..c668047c1f 100644 --- a/adapters/contxtful/contxtful_relay_test.go +++ b/adapters/contxtful/contxtful_relay_test.go @@ -5,9 +5,9 @@ import ( "testing" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/contxtful/contxtful_test.go b/adapters/contxtful/contxtful_test.go index b1fa229b6d..846144e9b4 100644 --- a/adapters/contxtful/contxtful_test.go +++ b/adapters/contxtful/contxtful_test.go @@ -9,11 +9,11 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/adapters/contxtful/params_test.go b/adapters/contxtful/params_test.go index bc7321f892..34831e1616 100644 --- a/adapters/contxtful/params_test.go +++ b/adapters/contxtful/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) { diff --git a/adapters/conversant/conversant.go b/adapters/conversant/conversant.go index 035ee14bae..67056dc569 100644 --- a/adapters/conversant/conversant.go +++ b/adapters/conversant/conversant.go @@ -8,11 +8,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type ConversantAdapter struct { diff --git a/adapters/conversant/conversant_test.go b/adapters/conversant/conversant_test.go index eeb5756471..563b229997 100644 --- a/adapters/conversant/conversant_test.go +++ b/adapters/conversant/conversant_test.go @@ -3,9 +3,9 @@ package conversant 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) { diff --git a/adapters/copper6ssp/copper6ssp.go b/adapters/copper6ssp/copper6ssp.go index 77154dd686..85f4674858 100644 --- a/adapters/copper6ssp/copper6ssp.go +++ b/adapters/copper6ssp/copper6ssp.go @@ -6,10 +6,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/copper6ssp/copper6ssp_test.go b/adapters/copper6ssp/copper6ssp_test.go index 75ca8ee404..9f98ce4ede 100644 --- a/adapters/copper6ssp/copper6ssp_test.go +++ b/adapters/copper6ssp/copper6ssp_test.go @@ -3,9 +3,9 @@ package copper6ssp 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) { diff --git a/adapters/copper6ssp/params_test.go b/adapters/copper6ssp/params_test.go index 427cf63b26..bd9d84ee3d 100644 --- a/adapters/copper6ssp/params_test.go +++ b/adapters/copper6ssp/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) { diff --git a/adapters/cpmstar/cpmstar.go b/adapters/cpmstar/cpmstar.go index 9aa3026c77..67a94ac239 100644 --- a/adapters/cpmstar/cpmstar.go +++ b/adapters/cpmstar/cpmstar.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type Adapter struct { diff --git a/adapters/cpmstar/cpmstar_test.go b/adapters/cpmstar/cpmstar_test.go index 478b898943..e007583af1 100644 --- a/adapters/cpmstar/cpmstar_test.go +++ b/adapters/cpmstar/cpmstar_test.go @@ -3,9 +3,9 @@ package cpmstar 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) { diff --git a/adapters/cpmstar/params_test.go b/adapters/cpmstar/params_test.go index aea148c82f..0fbb0d2530 100644 --- a/adapters/cpmstar/params_test.go +++ b/adapters/cpmstar/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" ) // This file actually intends to test static/bidder-params/cpmstar.json diff --git a/adapters/criteo/criteo.go b/adapters/criteo/criteo.go index 2bfa35ade0..6779a20f87 100644 --- a/adapters/criteo/criteo.go +++ b/adapters/criteo/criteo.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/criteo/criteo_test.go b/adapters/criteo/criteo_test.go index 70392c6cd5..f3fd11ba01 100644 --- a/adapters/criteo/criteo_test.go +++ b/adapters/criteo/criteo_test.go @@ -7,9 +7,9 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/criteo/params_test.go b/adapters/criteo/params_test.go index 240eeea43a..98f5f77f38 100644 --- a/adapters/criteo/params_test.go +++ b/adapters/criteo/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" ) // This file actually intends to test static/bidder-params/criteo.json diff --git a/adapters/cwire/cwire.go b/adapters/cwire/cwire.go index 2d297f78e9..f0b3fc2088 100644 --- a/adapters/cwire/cwire.go +++ b/adapters/cwire/cwire.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) /* diff --git a/adapters/cwire/cwire_test.go b/adapters/cwire/cwire_test.go index 726c3caf09..26b403d202 100644 --- a/adapters/cwire/cwire_test.go +++ b/adapters/cwire/cwire_test.go @@ -3,9 +3,9 @@ package cwire 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) { diff --git a/adapters/cwire/params_test.go b/adapters/cwire/params_test.go index 534a9c0923..b1577f86be 100644 --- a/adapters/cwire/params_test.go +++ b/adapters/cwire/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" ) // This file actually intends to test static/bidder-params/cwire.json diff --git a/adapters/datablocks/datablocks.go b/adapters/datablocks/datablocks.go index a0e318524d..7d911d98c0 100644 --- a/adapters/datablocks/datablocks.go +++ b/adapters/datablocks/datablocks.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 DatablocksAdapter struct { diff --git a/adapters/datablocks/datablocks_test.go b/adapters/datablocks/datablocks_test.go index f44204c7c5..762bf6cc0f 100644 --- a/adapters/datablocks/datablocks_test.go +++ b/adapters/datablocks/datablocks_test.go @@ -3,9 +3,9 @@ package datablocks 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/decenterads/decenterads.go b/adapters/decenterads/decenterads.go index 7981f60c97..26dd5634fb 100644 --- a/adapters/decenterads/decenterads.go +++ b/adapters/decenterads/decenterads.go @@ -8,11 +8,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/decenterads/decenterads_test.go b/adapters/decenterads/decenterads_test.go index ba3cefa989..97d72fba62 100644 --- a/adapters/decenterads/decenterads_test.go +++ b/adapters/decenterads/decenterads_test.go @@ -3,9 +3,9 @@ package decenterads 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) { diff --git a/adapters/decenterads/params_test.go b/adapters/decenterads/params_test.go index 7672892ed0..5e08265528 100644 --- a/adapters/decenterads/params_test.go +++ b/adapters/decenterads/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" ) // TestValidParams makes sure that the decenterads schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/deepintent/deepintent.go b/adapters/deepintent/deepintent.go index a1867cdadc..cb83e1ead7 100644 --- a/adapters/deepintent/deepintent.go +++ b/adapters/deepintent/deepintent.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const displayManager string = "di_prebid" diff --git a/adapters/deepintent/deepintent_test.go b/adapters/deepintent/deepintent_test.go index 6b2d216db3..4f8c2219b1 100644 --- a/adapters/deepintent/deepintent_test.go +++ b/adapters/deepintent/deepintent_test.go @@ -3,10 +3,10 @@ package deepintent import ( "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/deepintent/params_test.go b/adapters/deepintent/params_test.go index b45eaa67a8..e1f8cc1f8e 100644 --- a/adapters/deepintent/params_test.go +++ b/adapters/deepintent/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" ) // TestValidParams makes sure that the deepintent schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/definemedia/definemedia.go b/adapters/definemedia/definemedia.go index 7f775b88c3..fcfef769e0 100644 --- a/adapters/definemedia/definemedia.go +++ b/adapters/definemedia/definemedia.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/definemedia/definemedia_test.go b/adapters/definemedia/definemedia_test.go index 9d5b39b5b7..377c491041 100644 --- a/adapters/definemedia/definemedia_test.go +++ b/adapters/definemedia/definemedia_test.go @@ -3,9 +3,9 @@ package definemedia 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) { diff --git a/adapters/definemedia/params_test.go b/adapters/definemedia/params_test.go index bd3912719b..9af4ba1b20 100644 --- a/adapters/definemedia/params_test.go +++ b/adapters/definemedia/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) { diff --git a/adapters/dianomi/dianomi.go b/adapters/dianomi/dianomi.go index 5f16547de1..315a030a07 100644 --- a/adapters/dianomi/dianomi.go +++ b/adapters/dianomi/dianomi.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/dianomi/dianomi_test.go b/adapters/dianomi/dianomi_test.go index 23a42fa69c..da4a0d6644 100644 --- a/adapters/dianomi/dianomi_test.go +++ b/adapters/dianomi/dianomi_test.go @@ -3,9 +3,9 @@ package dianomi 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) { diff --git a/adapters/dianomi/params_test.go b/adapters/dianomi/params_test.go index 294bfa977f..dd9aeb1449 100644 --- a/adapters/dianomi/params_test.go +++ b/adapters/dianomi/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" ) // This file actually intends to test static/bidder-params/dianomi.json diff --git a/adapters/displayio/displayio.go b/adapters/displayio/displayio.go index cc9845d72f..2eff41e71d 100644 --- a/adapters/displayio/displayio.go +++ b/adapters/displayio/displayio.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/displayio/displayio_test.go b/adapters/displayio/displayio_test.go index b591abeb42..f7f32c8a8a 100644 --- a/adapters/displayio/displayio_test.go +++ b/adapters/displayio/displayio_test.go @@ -3,9 +3,9 @@ package displayio 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) { diff --git a/adapters/displayio/params_test.go b/adapters/displayio/params_test.go index 2e44954072..e11f1fadbc 100644 --- a/adapters/displayio/params_test.go +++ b/adapters/displayio/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) { diff --git a/adapters/dmx/dmx.go b/adapters/dmx/dmx.go index 458b497826..e2389146d0 100644 --- a/adapters/dmx/dmx.go +++ b/adapters/dmx/dmx.go @@ -10,11 +10,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type DmxAdapter struct { diff --git a/adapters/dmx/dmx_test.go b/adapters/dmx/dmx_test.go index cc46d28f31..9e37d0e345 100644 --- a/adapters/dmx/dmx_test.go +++ b/adapters/dmx/dmx_test.go @@ -6,11 +6,11 @@ import ( "testing" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" ) func TestFetchParams(t *testing.T) { diff --git a/adapters/dmx/params_test.go b/adapters/dmx/params_test.go index 49d89b330f..6e2e2ba071 100644 --- a/adapters/dmx/params_test.go +++ b/adapters/dmx/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) { diff --git a/adapters/driftpixel/driftpixel.go b/adapters/driftpixel/driftpixel.go index 65532a786c..e62303ed8a 100644 --- a/adapters/driftpixel/driftpixel.go +++ b/adapters/driftpixel/driftpixel.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/driftpixel/driftpixel_test.go b/adapters/driftpixel/driftpixel_test.go index 24bf8b1506..11d5d604f9 100644 --- a/adapters/driftpixel/driftpixel_test.go +++ b/adapters/driftpixel/driftpixel_test.go @@ -3,9 +3,9 @@ package driftpixel 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/driftpixel/params_test.go b/adapters/driftpixel/params_test.go index e8153f054c..225d949162 100644 --- a/adapters/driftpixel/params_test.go +++ b/adapters/driftpixel/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" ) var validParams = []string{ diff --git a/adapters/e_volution/evolution.go b/adapters/e_volution/evolution.go index 1b781c7405..3db5173ca6 100644 --- a/adapters/e_volution/evolution.go +++ b/adapters/e_volution/evolution.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/e_volution/evolution_test.go b/adapters/e_volution/evolution_test.go index 6a3dbe671e..3a16856945 100644 --- a/adapters/e_volution/evolution_test.go +++ b/adapters/e_volution/evolution_test.go @@ -3,9 +3,9 @@ package evolution 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/e_volution/params_test.go b/adapters/e_volution/params_test.go index 98558f88ab..ace2e32927 100644 --- a/adapters/e_volution/params_test.go +++ b/adapters/e_volution/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" ) var validParams = []string{ diff --git a/adapters/edge226/edge226.go b/adapters/edge226/edge226.go index 19804c8843..69f2b34646 100644 --- a/adapters/edge226/edge226.go +++ b/adapters/edge226/edge226.go @@ -6,10 +6,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/edge226/edge226_test.go b/adapters/edge226/edge226_test.go index cd3d9385ab..97927ef4c0 100644 --- a/adapters/edge226/edge226_test.go +++ b/adapters/edge226/edge226_test.go @@ -3,9 +3,9 @@ package edge226 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) { diff --git a/adapters/edge226/params_test.go b/adapters/edge226/params_test.go index 5161c349d7..9b5c210522 100644 --- a/adapters/edge226/params_test.go +++ b/adapters/edge226/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) { diff --git a/adapters/elementaltv/elementaltv.go b/adapters/elementaltv/elementaltv.go index 4495973313..4d84037b5c 100644 --- a/adapters/elementaltv/elementaltv.go +++ b/adapters/elementaltv/elementaltv.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" ) var bidHeaders http.Header = map[string][]string{ diff --git a/adapters/elementaltv/elementaltv_test.go b/adapters/elementaltv/elementaltv_test.go index 7dd0103848..c54c8c1570 100644 --- a/adapters/elementaltv/elementaltv_test.go +++ b/adapters/elementaltv/elementaltv_test.go @@ -3,9 +3,9 @@ package elementaltv 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" "github.com/stretchr/testify/require" ) diff --git a/adapters/elementaltv/params_test.go b/adapters/elementaltv/params_test.go index 9a125d126b..0c49095ca1 100644 --- a/adapters/elementaltv/params_test.go +++ b/adapters/elementaltv/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" "github.com/stretchr/testify/require" ) diff --git a/adapters/emtv/emtv.go b/adapters/emtv/emtv.go index c8814f8065..678c4bddca 100644 --- a/adapters/emtv/emtv.go +++ b/adapters/emtv/emtv.go @@ -7,11 +7,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/emtv/emtv_test.go b/adapters/emtv/emtv_test.go index 0dd4196af4..d2c36b2ae8 100644 --- a/adapters/emtv/emtv_test.go +++ b/adapters/emtv/emtv_test.go @@ -3,9 +3,9 @@ package emtv 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) { diff --git a/adapters/emtv/params_test.go b/adapters/emtv/params_test.go index cdea31b075..13631f3bb1 100644 --- a/adapters/emtv/params_test.go +++ b/adapters/emtv/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) { diff --git a/adapters/eplanning/eplanning.go b/adapters/eplanning/eplanning.go index fe05fee008..c7ba971586 100644 --- a/adapters/eplanning/eplanning.go +++ b/adapters/eplanning/eplanning.go @@ -12,11 +12,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "strconv" ) diff --git a/adapters/eplanning/eplanning_test.go b/adapters/eplanning/eplanning_test.go index 1d220184c6..3457b0023c 100644 --- a/adapters/eplanning/eplanning_test.go +++ b/adapters/eplanning/eplanning_test.go @@ -3,10 +3,10 @@ package eplanning import ( "testing" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "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) { diff --git a/adapters/epom/epom.go b/adapters/epom/epom.go index 82e44b409e..077cd2ba93 100644 --- a/adapters/epom/epom.go +++ b/adapters/epom/epom.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/epom/epom_test.go b/adapters/epom/epom_test.go index f90f2189d5..78f8ba428e 100644 --- a/adapters/epom/epom_test.go +++ b/adapters/epom/epom_test.go @@ -3,9 +3,9 @@ package epom 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) { diff --git a/adapters/escalax/escalax.go b/adapters/escalax/escalax.go index 867524a922..d11eea8f27 100644 --- a/adapters/escalax/escalax.go +++ b/adapters/escalax/escalax.go @@ -7,12 +7,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/escalax/escalax_test.go b/adapters/escalax/escalax_test.go index c4424bb10a..8d7ffcd0ee 100644 --- a/adapters/escalax/escalax_test.go +++ b/adapters/escalax/escalax_test.go @@ -3,9 +3,9 @@ package escalax 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/escalax/params_test.go b/adapters/escalax/params_test.go index 6e6036721a..93e605612e 100644 --- a/adapters/escalax/params_test.go +++ b/adapters/escalax/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" ) var validParams = []string{ diff --git a/adapters/exco/exco.go b/adapters/exco/exco.go index dc79c6ec1e..49f519691f 100644 --- a/adapters/exco/exco.go +++ b/adapters/exco/exco.go @@ -5,11 +5,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/exco/exco_test.go b/adapters/exco/exco_test.go index 77ab4afe88..faa955569e 100644 --- a/adapters/exco/exco_test.go +++ b/adapters/exco/exco_test.go @@ -3,9 +3,9 @@ package exco 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) { diff --git a/adapters/exco/params_test.go b/adapters/exco/params_test.go index eed4bc4b64..73fc0d657a 100644 --- a/adapters/exco/params_test.go +++ b/adapters/exco/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" ) // This file actually intends to test static/bidder-params/exco.json diff --git a/adapters/feedad/feedad.go b/adapters/feedad/feedad.go index 804027ee11..6a1c1314db 100644 --- a/adapters/feedad/feedad.go +++ b/adapters/feedad/feedad.go @@ -4,10 +4,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const feedAdAdapterVersion = "1.0.0" diff --git a/adapters/feedad/feedad_test.go b/adapters/feedad/feedad_test.go index 28993850df..66e7414f56 100644 --- a/adapters/feedad/feedad_test.go +++ b/adapters/feedad/feedad_test.go @@ -3,9 +3,9 @@ package feedad 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) { diff --git a/adapters/feedad/params_test.go b/adapters/feedad/params_test.go index a77ad9ae46..279b6c6c6d 100644 --- a/adapters/feedad/params_test.go +++ b/adapters/feedad/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) { diff --git a/adapters/flatads/flatads.go b/adapters/flatads/flatads.go index 0bf0b979e7..5bd1532ab7 100644 --- a/adapters/flatads/flatads.go +++ b/adapters/flatads/flatads.go @@ -6,12 +6,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/flatads/flatads_test.go b/adapters/flatads/flatads_test.go index b3b3cf33f7..6bd5187f01 100644 --- a/adapters/flatads/flatads_test.go +++ b/adapters/flatads/flatads_test.go @@ -3,9 +3,9 @@ package flatads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/flatads/params_test.go b/adapters/flatads/params_test.go index c58546399b..98c583695e 100644 --- a/adapters/flatads/params_test.go +++ b/adapters/flatads/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) { diff --git a/adapters/flipp/flipp.go b/adapters/flipp/flipp.go index 4ac5c31c76..fa8259b80a 100644 --- a/adapters/flipp/flipp.go +++ b/adapters/flipp/flipp.go @@ -13,11 +13,11 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/go-gdpr/vendorconsent" "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/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/uuidutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/uuidutil" ) const ( diff --git a/adapters/flipp/flipp_params.go b/adapters/flipp/flipp_params.go index 34d266a7d9..3e86337916 100644 --- a/adapters/flipp/flipp_params.go +++ b/adapters/flipp/flipp_params.go @@ -1,6 +1,6 @@ package flipp -import "github.com/prebid/prebid-server/v3/openrtb_ext" +import "github.com/prebid/prebid-server/v4/openrtb_ext" type CampaignRequestBodyUser struct { Key *string `json:"key"` diff --git a/adapters/flipp/flipp_test.go b/adapters/flipp/flipp_test.go index 8215dabe82..3676053f04 100644 --- a/adapters/flipp/flipp_test.go +++ b/adapters/flipp/flipp_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/flipp/params_test.go b/adapters/flipp/params_test.go index 24f30b0a62..01d4604c0a 100644 --- a/adapters/flipp/params_test.go +++ b/adapters/flipp/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) { diff --git a/adapters/freewheelssp/freewheelssp.go b/adapters/freewheelssp/freewheelssp.go index 111b05a60e..6e4ad67228 100644 --- a/adapters/freewheelssp/freewheelssp.go +++ b/adapters/freewheelssp/freewheelssp.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/freewheelssp/freewheelssp_test.go b/adapters/freewheelssp/freewheelssp_test.go index ba5e6cf9aa..d8d3350907 100644 --- a/adapters/freewheelssp/freewheelssp_test.go +++ b/adapters/freewheelssp/freewheelssp_test.go @@ -3,9 +3,9 @@ package freewheelssp 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) { diff --git a/adapters/frvradn/frvradn.go b/adapters/frvradn/frvradn.go index 5b21263b1a..4b307c7626 100644 --- a/adapters/frvradn/frvradn.go +++ b/adapters/frvradn/frvradn.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/frvradn/frvradn_test.go b/adapters/frvradn/frvradn_test.go index 514ef6c712..e69c10d865 100644 --- a/adapters/frvradn/frvradn_test.go +++ b/adapters/frvradn/frvradn_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/frvradn/params_test.go b/adapters/frvradn/params_test.go index 83e1ba631a..3d054db074 100644 --- a/adapters/frvradn/params_test.go +++ b/adapters/frvradn/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) { diff --git a/adapters/fwssp/fwssp.go b/adapters/fwssp/fwssp.go index 3ee896e156..ae916dc511 100644 --- a/adapters/fwssp/fwssp.go +++ b/adapters/fwssp/fwssp.go @@ -5,11 +5,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/fwssp/fwssp_test.go b/adapters/fwssp/fwssp_test.go index 7afd5197fd..5d9d6a8801 100644 --- a/adapters/fwssp/fwssp_test.go +++ b/adapters/fwssp/fwssp_test.go @@ -3,9 +3,9 @@ package fwssp 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) { diff --git a/adapters/fwssp/params_test.go b/adapters/fwssp/params_test.go index 366078c016..a413b51d35 100644 --- a/adapters/fwssp/params_test.go +++ b/adapters/fwssp/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) { diff --git a/adapters/gamma/gamma.go b/adapters/gamma/gamma.go index 66f99953fe..57edc810e8 100644 --- a/adapters/gamma/gamma.go +++ b/adapters/gamma/gamma.go @@ -9,11 +9,11 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type GammaAdapter struct { diff --git a/adapters/gamma/gamma_test.go b/adapters/gamma/gamma_test.go index 9556e83dc0..0c50d48662 100644 --- a/adapters/gamma/gamma_test.go +++ b/adapters/gamma/gamma_test.go @@ -3,9 +3,9 @@ package gamma 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) { diff --git a/adapters/gamma/params_test.go b/adapters/gamma/params_test.go index d377b50c3d..06f6d6faba 100644 --- a/adapters/gamma/params_test.go +++ b/adapters/gamma/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" ) // This file actually intends to test static/bidder-params/gamma.json diff --git a/adapters/gamoshi/gamoshi.go b/adapters/gamoshi/gamoshi.go index 4ba302506f..b4cd7841e5 100644 --- a/adapters/gamoshi/gamoshi.go +++ b/adapters/gamoshi/gamoshi.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type GamoshiAdapter struct { diff --git a/adapters/gamoshi/gamoshi_test.go b/adapters/gamoshi/gamoshi_test.go index aa20723b2d..ee572b2aca 100644 --- a/adapters/gamoshi/gamoshi_test.go +++ b/adapters/gamoshi/gamoshi_test.go @@ -3,9 +3,9 @@ package gamoshi 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 TestJsonSamplesWithConfiguredURI(t *testing.T) { diff --git a/adapters/gamoshi/params_test.go b/adapters/gamoshi/params_test.go index 429ed96ad8..21f887d686 100644 --- a/adapters/gamoshi/params_test.go +++ b/adapters/gamoshi/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" ) // This file actually intends to test static/bidder-params/gamoshi.json diff --git a/adapters/globalsun/globalsun.go b/adapters/globalsun/globalsun.go index a2b2dc5b9a..cbdc899e80 100644 --- a/adapters/globalsun/globalsun.go +++ b/adapters/globalsun/globalsun.go @@ -7,11 +7,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/globalsun/globalsun_test.go b/adapters/globalsun/globalsun_test.go index e34805f68f..cfbebe3135 100644 --- a/adapters/globalsun/globalsun_test.go +++ b/adapters/globalsun/globalsun_test.go @@ -3,9 +3,9 @@ package globalsun 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) { diff --git a/adapters/globalsun/params_test.go b/adapters/globalsun/params_test.go index b4fe0ede7a..9847ce3d29 100644 --- a/adapters/globalsun/params_test.go +++ b/adapters/globalsun/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) { diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index 5c500e63ce..3d47a4b3dd 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -5,11 +5,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/goldbach/goldbach_test.go b/adapters/goldbach/goldbach_test.go index a1f046adfe..55c5ea75fe 100644 --- a/adapters/goldbach/goldbach_test.go +++ b/adapters/goldbach/goldbach_test.go @@ -3,9 +3,9 @@ package goldbach 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" "github.com/stretchr/testify/require" ) diff --git a/adapters/goldbach/params_test.go b/adapters/goldbach/params_test.go index b03d182247..0ef079fa80 100644 --- a/adapters/goldbach/params_test.go +++ b/adapters/goldbach/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" "github.com/stretchr/testify/require" ) diff --git a/adapters/grid/grid.go b/adapters/grid/grid.go index ad61058fed..b0b4304f73 100644 --- a/adapters/grid/grid.go +++ b/adapters/grid/grid.go @@ -9,12 +9,12 @@ import ( "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" - "github.com/prebid/prebid-server/v3/util/maputil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/maputil" ) type GridAdapter struct { diff --git a/adapters/grid/grid_test.go b/adapters/grid/grid_test.go index bf7bfe547f..652ae514cc 100644 --- a/adapters/grid/grid_test.go +++ b/adapters/grid/grid_test.go @@ -3,9 +3,9 @@ package grid 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) { diff --git a/adapters/gumgum/gumgum.go b/adapters/gumgum/gumgum.go index 943ccfdf14..08681a48a5 100644 --- a/adapters/gumgum/gumgum.go +++ b/adapters/gumgum/gumgum.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // adapter implements Bidder interface. diff --git a/adapters/gumgum/gumgum_test.go b/adapters/gumgum/gumgum_test.go index 6386818803..852f672678 100644 --- a/adapters/gumgum/gumgum_test.go +++ b/adapters/gumgum/gumgum_test.go @@ -3,9 +3,9 @@ package gumgum 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) { diff --git a/adapters/gumgum/params_test.go b/adapters/gumgum/params_test.go index 514ab1d8c7..a67c7695e4 100644 --- a/adapters/gumgum/params_test.go +++ b/adapters/gumgum/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) { diff --git a/adapters/huaweiads/huaweiads.go b/adapters/huaweiads/huaweiads.go index 144f5e2220..6466e2b9b7 100644 --- a/adapters/huaweiads/huaweiads.go +++ b/adapters/huaweiads/huaweiads.go @@ -20,12 +20,12 @@ import ( nativeRequests "github.com/prebid/openrtb/v20/native1/request" nativeResponse "github.com/prebid/openrtb/v20/native1/response" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const huaweiAdxApiVersion = "3.4" diff --git a/adapters/huaweiads/huaweiads_test.go b/adapters/huaweiads/huaweiads_test.go index c6fd17feaa..aa6e788afa 100644 --- a/adapters/huaweiads/huaweiads_test.go +++ b/adapters/huaweiads/huaweiads_test.go @@ -3,9 +3,9 @@ package huaweiads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/huaweiads/params_test.go b/adapters/huaweiads/params_test.go index 9c4b5b36d2..22c1d1e527 100644 --- a/adapters/huaweiads/params_test.go +++ b/adapters/huaweiads/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) { diff --git a/adapters/imds/imds.go b/adapters/imds/imds.go index a5f53d6036..18a7284612 100644 --- a/adapters/imds/imds.go +++ b/adapters/imds/imds.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" ) const adapterVersion string = "pbs-go/1.0.0" diff --git a/adapters/imds/imds_test.go b/adapters/imds/imds_test.go index 40a00462c1..525b2e6de5 100644 --- a/adapters/imds/imds_test.go +++ b/adapters/imds/imds_test.go @@ -3,9 +3,9 @@ package imds 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/imds/params_test.go b/adapters/imds/params_test.go index d98fe04cd1..2aa4a6b5e4 100644 --- a/adapters/imds/params_test.go +++ b/adapters/imds/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" ) // This file actually intends to test static/bidder-params/imds.json diff --git a/adapters/impactify/impactify.go b/adapters/impactify/impactify.go index 52f20ddd8d..eca008f150 100644 --- a/adapters/impactify/impactify.go +++ b/adapters/impactify/impactify.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/impactify/impactify_test.go b/adapters/impactify/impactify_test.go index 2385c5c64a..31be74f2fa 100644 --- a/adapters/impactify/impactify_test.go +++ b/adapters/impactify/impactify_test.go @@ -3,9 +3,9 @@ package impactify 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) { diff --git a/adapters/impactify/params_test.go b/adapters/impactify/params_test.go index 589e090172..d8b4626092 100644 --- a/adapters/impactify/params_test.go +++ b/adapters/impactify/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) { diff --git a/adapters/improvedigital/improvedigital.go b/adapters/improvedigital/improvedigital.go index 13534cc6dd..3821087d14 100644 --- a/adapters/improvedigital/improvedigital.go +++ b/adapters/improvedigital/improvedigital.go @@ -9,11 +9,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/improvedigital/improvedigital_test.go b/adapters/improvedigital/improvedigital_test.go index cd00aeaab7..ecb0007f9c 100644 --- a/adapters/improvedigital/improvedigital_test.go +++ b/adapters/improvedigital/improvedigital_test.go @@ -3,9 +3,9 @@ package improvedigital 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) { diff --git a/adapters/improvedigital/params_test.go b/adapters/improvedigital/params_test.go index abb1491fb0..4b3c9cea9a 100644 --- a/adapters/improvedigital/params_test.go +++ b/adapters/improvedigital/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) { diff --git a/adapters/infoawarebidder.go b/adapters/infoawarebidder.go index 6ccc039b48..414a9d3599 100644 --- a/adapters/infoawarebidder.go +++ b/adapters/infoawarebidder.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "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/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // InfoAwareBidder wraps a Bidder to ensure all requests abide by the capabilities and diff --git a/adapters/infoawarebidder_test.go b/adapters/infoawarebidder_test.go index 5a28e506cc..1008cadcbe 100644 --- a/adapters/infoawarebidder_test.go +++ b/adapters/infoawarebidder_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "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/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/infytv/infytv.go b/adapters/infytv/infytv.go index 1d0c70123a..1d2a7b29d8 100644 --- a/adapters/infytv/infytv.go +++ b/adapters/infytv/infytv.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/infytv/infytv_test.go b/adapters/infytv/infytv_test.go index 85a4dd4b9b..c9d8c140cb 100644 --- a/adapters/infytv/infytv_test.go +++ b/adapters/infytv/infytv_test.go @@ -3,9 +3,9 @@ package infytv 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/infytv/params_test.go b/adapters/infytv/params_test.go index 671a5a4e71..7ab22349be 100644 --- a/adapters/infytv/params_test.go +++ b/adapters/infytv/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) { diff --git a/adapters/inmobi/inmobi.go b/adapters/inmobi/inmobi.go index f79151bea8..6aa6422127 100644 --- a/adapters/inmobi/inmobi.go +++ b/adapters/inmobi/inmobi.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type InMobiAdapter struct { diff --git a/adapters/inmobi/inmobi_test.go b/adapters/inmobi/inmobi_test.go index 89884a8dde..67f095f86a 100644 --- a/adapters/inmobi/inmobi_test.go +++ b/adapters/inmobi/inmobi_test.go @@ -3,9 +3,9 @@ package inmobi 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) { diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index e6e3866376..38d25c41f1 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -7,12 +7,12 @@ import ( "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" - "github.com/prebid/prebid-server/v3/util/mathutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/mathutil" ) type ext struct { diff --git a/adapters/insticator/insticator_test.go b/adapters/insticator/insticator_test.go index 1000697800..6e80fa4eac 100644 --- a/adapters/insticator/insticator_test.go +++ b/adapters/insticator/insticator_test.go @@ -3,9 +3,9 @@ package insticator 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) { diff --git a/adapters/insticator/params_test.go b/adapters/insticator/params_test.go index 47d2bdf44f..85089bb1ec 100644 --- a/adapters/insticator/params_test.go +++ b/adapters/insticator/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" ) // This file actually intends to test static/bidder-params/Insticator.json diff --git a/adapters/intenze/intenze.go b/adapters/intenze/intenze.go index 6a1994ea12..2a9ec562b8 100644 --- a/adapters/intenze/intenze.go +++ b/adapters/intenze/intenze.go @@ -7,12 +7,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/intenze/intenze_test.go b/adapters/intenze/intenze_test.go index 3ea1247ad5..00d97a6b31 100644 --- a/adapters/intenze/intenze_test.go +++ b/adapters/intenze/intenze_test.go @@ -3,9 +3,9 @@ package intenze 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/intenze/params_test.go b/adapters/intenze/params_test.go index 2e2b66ef74..51fbd2dc38 100644 --- a/adapters/intenze/params_test.go +++ b/adapters/intenze/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" ) var validParams = []string{ diff --git a/adapters/interactiveoffers/interactiveoffers.go b/adapters/interactiveoffers/interactiveoffers.go index 6eaee7a978..3c3d750bbb 100644 --- a/adapters/interactiveoffers/interactiveoffers.go +++ b/adapters/interactiveoffers/interactiveoffers.go @@ -7,12 +7,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/interactiveoffers/interactiveoffers_test.go b/adapters/interactiveoffers/interactiveoffers_test.go index df116c60a5..16c5eeb958 100644 --- a/adapters/interactiveoffers/interactiveoffers_test.go +++ b/adapters/interactiveoffers/interactiveoffers_test.go @@ -3,9 +3,9 @@ package interactiveoffers 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) { diff --git a/adapters/interactiveoffers/params_test.go b/adapters/interactiveoffers/params_test.go index 631d8f44ae..cb15379164 100644 --- a/adapters/interactiveoffers/params_test.go +++ b/adapters/interactiveoffers/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) { diff --git a/adapters/invibes/invibes.go b/adapters/invibes/invibes.go index 4657be2974..a157fddff8 100644 --- a/adapters/invibes/invibes.go +++ b/adapters/invibes/invibes.go @@ -10,13 +10,13 @@ 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/metrics" - "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/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const adapterVersion = "prebid_1.0.0" diff --git a/adapters/invibes/invibes_test.go b/adapters/invibes/invibes_test.go index be8dda3ffd..1c27e09edb 100644 --- a/adapters/invibes/invibes_test.go +++ b/adapters/invibes/invibes_test.go @@ -3,9 +3,9 @@ package invibes 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/invibes/params_test.go b/adapters/invibes/params_test.go index 48be52c4ba..2a5394488b 100644 --- a/adapters/invibes/params_test.go +++ b/adapters/invibes/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) { diff --git a/adapters/iqx/iqx.go b/adapters/iqx/iqx.go index c3519b10b1..ea2100ef0d 100644 --- a/adapters/iqx/iqx.go +++ b/adapters/iqx/iqx.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/iqx/iqxtest_test.go b/adapters/iqx/iqxtest_test.go index 190560d6de..6504c0e1d4 100644 --- a/adapters/iqx/iqxtest_test.go +++ b/adapters/iqx/iqxtest_test.go @@ -3,9 +3,9 @@ package iqx 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/iqx/params_test.go b/adapters/iqx/params_test.go index 4b687728b2..883bb46a37 100644 --- a/adapters/iqx/params_test.go +++ b/adapters/iqx/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" ) var validParams = []string{ diff --git a/adapters/iqzone/iqzone.go b/adapters/iqzone/iqzone.go index 9becbfbb89..2aaf90eeb7 100644 --- a/adapters/iqzone/iqzone.go +++ b/adapters/iqzone/iqzone.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/iqzone/iqzone_test.go b/adapters/iqzone/iqzone_test.go index 37ba833f50..bda00b1527 100644 --- a/adapters/iqzone/iqzone_test.go +++ b/adapters/iqzone/iqzone_test.go @@ -3,9 +3,9 @@ package iqzone 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) { diff --git a/adapters/iqzone/params_test.go b/adapters/iqzone/params_test.go index 4d3aa165a6..f1b6ba1c4d 100644 --- a/adapters/iqzone/params_test.go +++ b/adapters/iqzone/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) { diff --git a/adapters/ix/ix.go b/adapters/ix/ix.go index b24d99eff3..b09e8511c5 100644 --- a/adapters/ix/ix.go +++ b/adapters/ix/ix.go @@ -7,13 +7,13 @@ import ( "sort" "strings" - "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/version" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/version" "github.com/prebid/openrtb/v20/native1" native1response "github.com/prebid/openrtb/v20/native1/response" diff --git a/adapters/ix/ix_test.go b/adapters/ix/ix_test.go index d46b69adff..eb6b96f42a 100644 --- a/adapters/ix/ix_test.go +++ b/adapters/ix/ix_test.go @@ -4,11 +4,11 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/adapters" - "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/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/prebid/openrtb/v20/adcom1" diff --git a/adapters/ix/params_test.go b/adapters/ix/params_test.go index 90d591b50c..e1f4b44663 100644 --- a/adapters/ix/params_test.go +++ b/adapters/ix/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) { diff --git a/adapters/jixie/jixie.go b/adapters/jixie/jixie.go index d0411d1e5e..9ab479664f 100644 --- a/adapters/jixie/jixie.go +++ b/adapters/jixie/jixie.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/jixie/jixie_test.go b/adapters/jixie/jixie_test.go index 6fe4fa24ce..cf217eb4f0 100644 --- a/adapters/jixie/jixie_test.go +++ b/adapters/jixie/jixie_test.go @@ -3,9 +3,9 @@ package jixie 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) { diff --git a/adapters/jixie/params_test.go b/adapters/jixie/params_test.go index 653f3f86e1..1cd650a94d 100644 --- a/adapters/jixie/params_test.go +++ b/adapters/jixie/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) { diff --git a/adapters/kargo/kargo.go b/adapters/kargo/kargo.go index da12ef68ca..c75b681280 100644 --- a/adapters/kargo/kargo.go +++ b/adapters/kargo/kargo.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/kargo/kargo_test.go b/adapters/kargo/kargo_test.go index 0e7eb83bc1..fe3ba8bab5 100644 --- a/adapters/kargo/kargo_test.go +++ b/adapters/kargo/kargo_test.go @@ -3,9 +3,9 @@ package kargo 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) { diff --git a/adapters/kargo/params_test.go b/adapters/kargo/params_test.go index 91b46fbc4e..2bd805d0a3 100644 --- a/adapters/kargo/params_test.go +++ b/adapters/kargo/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) { diff --git a/adapters/kayzen/kayzen.go b/adapters/kayzen/kayzen.go index 680362603e..9c866918a9 100644 --- a/adapters/kayzen/kayzen.go +++ b/adapters/kayzen/kayzen.go @@ -7,12 +7,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/kayzen/kayzen_test.go b/adapters/kayzen/kayzen_test.go index 6b3776ddba..3b0644906e 100644 --- a/adapters/kayzen/kayzen_test.go +++ b/adapters/kayzen/kayzen_test.go @@ -3,9 +3,9 @@ package kayzen 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/kayzen/params_test.go b/adapters/kayzen/params_test.go index 647f77d134..66666e1980 100644 --- a/adapters/kayzen/params_test.go +++ b/adapters/kayzen/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" ) var validParams = []string{ diff --git a/adapters/kidoz/kidoz.go b/adapters/kidoz/kidoz.go index 88628085ef..df9d1fe457 100644 --- a/adapters/kidoz/kidoz.go +++ b/adapters/kidoz/kidoz.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type KidozAdapter struct { diff --git a/adapters/kidoz/kidoz_test.go b/adapters/kidoz/kidoz_test.go index 8923518559..59b1b63f22 100644 --- a/adapters/kidoz/kidoz_test.go +++ b/adapters/kidoz/kidoz_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/kidoz/params_test.go b/adapters/kidoz/params_test.go index 1dfa3e8955..87521a27fd 100644 --- a/adapters/kidoz/params_test.go +++ b/adapters/kidoz/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) { diff --git a/adapters/kiviads/kiviads.go b/adapters/kiviads/kiviads.go index ad5dcb58e2..98ab0dc0ca 100644 --- a/adapters/kiviads/kiviads.go +++ b/adapters/kiviads/kiviads.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/kiviads/kiviads_test.go b/adapters/kiviads/kiviads_test.go index dd83e0d177..c754fea012 100644 --- a/adapters/kiviads/kiviads_test.go +++ b/adapters/kiviads/kiviads_test.go @@ -3,9 +3,9 @@ package kiviads 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) { diff --git a/adapters/kiviads/params_test.go b/adapters/kiviads/params_test.go index 0192795006..12a46ce732 100644 --- a/adapters/kiviads/params_test.go +++ b/adapters/kiviads/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) { diff --git a/adapters/kobler/kobler.go b/adapters/kobler/kobler.go index cb1a1acaa7..30c88ba55f 100644 --- a/adapters/kobler/kobler.go +++ b/adapters/kobler/kobler.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/kobler/kobler_test.go b/adapters/kobler/kobler_test.go index 0cd924b8ba..622a43c8dc 100644 --- a/adapters/kobler/kobler_test.go +++ b/adapters/kobler/kobler_test.go @@ -3,9 +3,9 @@ package kobler 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) { diff --git a/adapters/kobler/params_test.go b/adapters/kobler/params_test.go index bc8b3ec9bf..d40dbfba14 100644 --- a/adapters/kobler/params_test.go +++ b/adapters/kobler/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" ) var validParams = []string{ diff --git a/adapters/krushmedia/krushmedia.go b/adapters/krushmedia/krushmedia.go index fd2a0adf8b..3d95cd94fb 100644 --- a/adapters/krushmedia/krushmedia.go +++ b/adapters/krushmedia/krushmedia.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 KrushmediaAdapter struct { diff --git a/adapters/krushmedia/krushmedia_test.go b/adapters/krushmedia/krushmedia_test.go index 26117ce103..f39f62993b 100644 --- a/adapters/krushmedia/krushmedia_test.go +++ b/adapters/krushmedia/krushmedia_test.go @@ -3,9 +3,9 @@ package krushmedia 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/krushmedia/params_test.go b/adapters/krushmedia/params_test.go index babf6b205d..0fc1a0fbb7 100644 --- a/adapters/krushmedia/params_test.go +++ b/adapters/krushmedia/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" ) var validParams = []string{ diff --git a/adapters/kueezrtb/kueezrtb.go b/adapters/kueezrtb/kueezrtb.go index 0edfbffd38..cd2000747d 100644 --- a/adapters/kueezrtb/kueezrtb.go +++ b/adapters/kueezrtb/kueezrtb.go @@ -4,11 +4,11 @@ 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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "net/http" "net/url" ) diff --git a/adapters/kueezrtb/kueezrtb_test.go b/adapters/kueezrtb/kueezrtb_test.go index b62eff292d..82b233a6fa 100644 --- a/adapters/kueezrtb/kueezrtb_test.go +++ b/adapters/kueezrtb/kueezrtb_test.go @@ -3,9 +3,9 @@ package kueezrtb 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) { diff --git a/adapters/kueezrtb/params_test.go b/adapters/kueezrtb/params_test.go index 33e5ea0a64..4fdf113bd7 100644 --- a/adapters/kueezrtb/params_test.go +++ b/adapters/kueezrtb/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) { diff --git a/adapters/lemmadigital/lemmadigital.go b/adapters/lemmadigital/lemmadigital.go index 16d93d47be..a098699dc8 100644 --- a/adapters/lemmadigital/lemmadigital.go +++ b/adapters/lemmadigital/lemmadigital.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/lemmadigital/lemmadigital_test.go b/adapters/lemmadigital/lemmadigital_test.go index d3e770bb63..a6705f391f 100644 --- a/adapters/lemmadigital/lemmadigital_test.go +++ b/adapters/lemmadigital/lemmadigital_test.go @@ -3,9 +3,9 @@ package lemmadigital 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) { diff --git a/adapters/lemmadigital/params_test.go b/adapters/lemmadigital/params_test.go index c8c739ff59..b9335a1efa 100644 --- a/adapters/lemmadigital/params_test.go +++ b/adapters/lemmadigital/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" ) // Tests for static/bidder-params/lemmadigital.json diff --git a/adapters/limelightDigital/limelightDigital.go b/adapters/limelightDigital/limelightDigital.go index 18ba5dd6f7..47566812cc 100644 --- a/adapters/limelightDigital/limelightDigital.go +++ b/adapters/limelightDigital/limelightDigital.go @@ -10,12 +10,12 @@ import ( "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/limelightDigital/limelightDigital_test.go b/adapters/limelightDigital/limelightDigital_test.go index 2b36ee573d..1f838245cb 100644 --- a/adapters/limelightDigital/limelightDigital_test.go +++ b/adapters/limelightDigital/limelightDigital_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/limelightDigital/params_test.go b/adapters/limelightDigital/params_test.go index 04c49d8373..a4aaa4466c 100644 --- a/adapters/limelightDigital/params_test.go +++ b/adapters/limelightDigital/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) { diff --git a/adapters/lm_kiviads/lmkiviads.go b/adapters/lm_kiviads/lmkiviads.go index bc4e48b1d7..e94a9a9aba 100644 --- a/adapters/lm_kiviads/lmkiviads.go +++ b/adapters/lm_kiviads/lmkiviads.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/lm_kiviads/lmkiviads_test.go b/adapters/lm_kiviads/lmkiviads_test.go index 34ea2bf467..05d8458250 100644 --- a/adapters/lm_kiviads/lmkiviads_test.go +++ b/adapters/lm_kiviads/lmkiviads_test.go @@ -3,9 +3,9 @@ package lmkiviads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/lm_kiviads/params_test.go b/adapters/lm_kiviads/params_test.go index 00f76bca95..2d77754e06 100644 --- a/adapters/lm_kiviads/params_test.go +++ b/adapters/lm_kiviads/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" ) var validParams = []string{ diff --git a/adapters/lockerdome/lockerdome.go b/adapters/lockerdome/lockerdome.go index 2206b82015..ac79a67262 100644 --- a/adapters/lockerdome/lockerdome.go +++ b/adapters/lockerdome/lockerdome.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const unexpectedStatusCodeMessage = "Unexpected status code: %d. Run with request.debug = 1 for more info" diff --git a/adapters/lockerdome/lockerdome_test.go b/adapters/lockerdome/lockerdome_test.go index b0c12083e4..3d2de082dd 100644 --- a/adapters/lockerdome/lockerdome_test.go +++ b/adapters/lockerdome/lockerdome_test.go @@ -3,9 +3,9 @@ package lockerdome 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) { diff --git a/adapters/lockerdome/params_test.go b/adapters/lockerdome/params_test.go index 50504b68d2..3a15f24855 100644 --- a/adapters/lockerdome/params_test.go +++ b/adapters/lockerdome/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" ) // This file tests static/bidder-params/lockerdome.json diff --git a/adapters/logan/logan.go b/adapters/logan/logan.go index a5f995108f..bff7cbcbec 100644 --- a/adapters/logan/logan.go +++ b/adapters/logan/logan.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/logan/logan_test.go b/adapters/logan/logan_test.go index 8e677c5585..a465282d71 100644 --- a/adapters/logan/logan_test.go +++ b/adapters/logan/logan_test.go @@ -3,9 +3,9 @@ package logan 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) { diff --git a/adapters/logan/params_test.go b/adapters/logan/params_test.go index 76c8cb3dd8..c09b6c4f83 100644 --- a/adapters/logan/params_test.go +++ b/adapters/logan/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) { diff --git a/adapters/logicad/logicad.go b/adapters/logicad/logicad.go index a1dc40fdcf..8f81e4a7cd 100644 --- a/adapters/logicad/logicad.go +++ b/adapters/logicad/logicad.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type LogicadAdapter struct { diff --git a/adapters/logicad/logicad_test.go b/adapters/logicad/logicad_test.go index a15d381cbb..c58f39085c 100644 --- a/adapters/logicad/logicad_test.go +++ b/adapters/logicad/logicad_test.go @@ -3,9 +3,9 @@ package logicad 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) { diff --git a/adapters/logicad/params_test.go b/adapters/logicad/params_test.go index 06f15d9d1b..9a15906c8f 100644 --- a/adapters/logicad/params_test.go +++ b/adapters/logicad/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) { diff --git a/adapters/loopme/loopme.go b/adapters/loopme/loopme.go index d4b9d7906f..fde97aee06 100644 --- a/adapters/loopme/loopme.go +++ b/adapters/loopme/loopme.go @@ -6,10 +6,10 @@ import ( "net/http" "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/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type adapter struct { diff --git a/adapters/loopme/loopme_test.go b/adapters/loopme/loopme_test.go index ca293c45ce..003a240c27 100644 --- a/adapters/loopme/loopme_test.go +++ b/adapters/loopme/loopme_test.go @@ -3,9 +3,9 @@ package loopme 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) { diff --git a/adapters/loopme/params_test.go b/adapters/loopme/params_test.go index 12ddf8e985..9ff1acf3d4 100644 --- a/adapters/loopme/params_test.go +++ b/adapters/loopme/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" ) // This file actually intends to test static/bidder-params/loopme.json diff --git a/adapters/loyal/loyal.go b/adapters/loyal/loyal.go index efe069c638..8a16c4f5bd 100644 --- a/adapters/loyal/loyal.go +++ b/adapters/loyal/loyal.go @@ -7,10 +7,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/loyal/loyal_test.go b/adapters/loyal/loyal_test.go index 1836b267be..5664860199 100644 --- a/adapters/loyal/loyal_test.go +++ b/adapters/loyal/loyal_test.go @@ -3,9 +3,9 @@ package loyal 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) { diff --git a/adapters/loyal/params_test.go b/adapters/loyal/params_test.go index e0c47d5030..ae1ba114ee 100644 --- a/adapters/loyal/params_test.go +++ b/adapters/loyal/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) { diff --git a/adapters/lunamedia/lunamedia.go b/adapters/lunamedia/lunamedia.go index 3db1b12ad4..2c5b87aa6c 100644 --- a/adapters/lunamedia/lunamedia.go +++ b/adapters/lunamedia/lunamedia.go @@ -7,12 +7,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 LunaMediaAdapter struct { diff --git a/adapters/lunamedia/lunamedia_test.go b/adapters/lunamedia/lunamedia_test.go index 8677fbb297..b04789370a 100644 --- a/adapters/lunamedia/lunamedia_test.go +++ b/adapters/lunamedia/lunamedia_test.go @@ -3,9 +3,9 @@ package lunamedia 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/lunamedia/params_test.go b/adapters/lunamedia/params_test.go index b78b94934d..6ff7240b5d 100644 --- a/adapters/lunamedia/params_test.go +++ b/adapters/lunamedia/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) { diff --git a/adapters/mabidder/mabidder.go b/adapters/mabidder/mabidder.go index 25d2830ef9..99a37ce8bd 100644 --- a/adapters/mabidder/mabidder.go +++ b/adapters/mabidder/mabidder.go @@ -4,10 +4,10 @@ import ( "encoding/json" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type serverResponse struct { diff --git a/adapters/mabidder/mabidder_test.go b/adapters/mabidder/mabidder_test.go index f821752e9b..8aa74d5b03 100644 --- a/adapters/mabidder/mabidder_test.go +++ b/adapters/mabidder/mabidder_test.go @@ -3,9 +3,9 @@ package mabidder 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) { diff --git a/adapters/mabidder/params_test.go b/adapters/mabidder/params_test.go index bd4162448f..1d216b4d42 100644 --- a/adapters/mabidder/params_test.go +++ b/adapters/mabidder/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) { diff --git a/adapters/madsense/madsense.go b/adapters/madsense/madsense.go index 5cf32d64d5..d827fcb36c 100644 --- a/adapters/madsense/madsense.go +++ b/adapters/madsense/madsense.go @@ -5,11 +5,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/madsense/madsense_test.go b/adapters/madsense/madsense_test.go index 8093066ac5..f1f6c1f3a4 100644 --- a/adapters/madsense/madsense_test.go +++ b/adapters/madsense/madsense_test.go @@ -1,9 +1,9 @@ package madsense import ( - "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" "github.com/stretchr/testify/require" "testing" ) diff --git a/adapters/madsense/params_test.go b/adapters/madsense/params_test.go index de59706745..32283395ad 100644 --- a/adapters/madsense/params_test.go +++ b/adapters/madsense/params_test.go @@ -2,7 +2,7 @@ package madsense import ( "encoding/json" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/require" "testing" ) diff --git a/adapters/madsense/utils.go b/adapters/madsense/utils.go index 992d136330..fb1d168d6f 100644 --- a/adapters/madsense/utils.go +++ b/adapters/madsense/utils.go @@ -5,10 +5,10 @@ import ( "net/http" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/errortypes" - "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/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpMadSense, error) { diff --git a/adapters/madvertise/madvertise.go b/adapters/madvertise/madvertise.go index d8c6fc3953..bcc95ed889 100644 --- a/adapters/madvertise/madvertise.go +++ b/adapters/madvertise/madvertise.go @@ -8,12 +8,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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/madvertise/madvertise_test.go b/adapters/madvertise/madvertise_test.go index e402ae4dc7..edfb3f3356 100644 --- a/adapters/madvertise/madvertise_test.go +++ b/adapters/madvertise/madvertise_test.go @@ -3,9 +3,9 @@ package madvertise 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/madvertise/params_test.go b/adapters/madvertise/params_test.go index c155d5beda..f5f1af383f 100644 --- a/adapters/madvertise/params_test.go +++ b/adapters/madvertise/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" ) // This file actually intends to test static/bidder-params/Madvertise.json diff --git a/adapters/marsmedia/marsmedia.go b/adapters/marsmedia/marsmedia.go index 92bfa0dc9f..b9548e77f9 100644 --- a/adapters/marsmedia/marsmedia.go +++ b/adapters/marsmedia/marsmedia.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type MarsmediaAdapter struct { diff --git a/adapters/marsmedia/marsmedia_test.go b/adapters/marsmedia/marsmedia_test.go index 4164d433fd..5b3da23b36 100644 --- a/adapters/marsmedia/marsmedia_test.go +++ b/adapters/marsmedia/marsmedia_test.go @@ -3,9 +3,9 @@ package marsmedia 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) { diff --git a/adapters/marsmedia/params_test.go b/adapters/marsmedia/params_test.go index 7961d21455..e2c00c9683 100644 --- a/adapters/marsmedia/params_test.go +++ b/adapters/marsmedia/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" ) // This file actually intends to test static/bidder-params/marsmedia.json diff --git a/adapters/mediago/mediago.go b/adapters/mediago/mediago.go index dc7ee01b9f..428e6cb15f 100644 --- a/adapters/mediago/mediago.go +++ b/adapters/mediago/mediago.go @@ -9,12 +9,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/mediago/mediago_test.go b/adapters/mediago/mediago_test.go index d6a480c828..944643e417 100644 --- a/adapters/mediago/mediago_test.go +++ b/adapters/mediago/mediago_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/mediago/params_test.go b/adapters/mediago/params_test.go index c1a7fbd3e4..9639863066 100644 --- a/adapters/mediago/params_test.go +++ b/adapters/mediago/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) { diff --git a/adapters/medianet/medianet.go b/adapters/medianet/medianet.go index 08a1ae021f..06ae131f69 100644 --- a/adapters/medianet/medianet.go +++ b/adapters/medianet/medianet.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/medianet/medianet_test.go b/adapters/medianet/medianet_test.go index 8721c6984c..84efea60bc 100644 --- a/adapters/medianet/medianet_test.go +++ b/adapters/medianet/medianet_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/medianet/params_test.go b/adapters/medianet/params_test.go index 15cd4acbab..78c520a8f1 100644 --- a/adapters/medianet/params_test.go +++ b/adapters/medianet/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" ) // This file actually intends to test static/bidder-params/medianet.json diff --git a/adapters/mediasquare/mediasquare.go b/adapters/mediasquare/mediasquare.go index 4a7943d058..8b232b44a8 100644 --- a/adapters/mediasquare/mediasquare.go +++ b/adapters/mediasquare/mediasquare.go @@ -5,11 +5,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/mediasquare/mediasquare_test.go b/adapters/mediasquare/mediasquare_test.go index 091f13ba19..25df6fb351 100644 --- a/adapters/mediasquare/mediasquare_test.go +++ b/adapters/mediasquare/mediasquare_test.go @@ -4,10 +4,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/mediasquare/params_test.go b/adapters/mediasquare/params_test.go index c9d2d5fe01..4906679e28 100644 --- a/adapters/mediasquare/params_test.go +++ b/adapters/mediasquare/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) { diff --git a/adapters/mediasquare/parsers.go b/adapters/mediasquare/parsers.go index 6e7dcfa86b..ec531456c1 100644 --- a/adapters/mediasquare/parsers.go +++ b/adapters/mediasquare/parsers.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // parserDSA: Struct used to extracts dsa content of a jsonutil. diff --git a/adapters/mediasquare/structs.go b/adapters/mediasquare/structs.go index 23e15f4068..dbda186a28 100644 --- a/adapters/mediasquare/structs.go +++ b/adapters/mediasquare/structs.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/version" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/version" ) // msqResponse: Bid-Response sent by mediasquare. diff --git a/adapters/mediasquare/utils.go b/adapters/mediasquare/utils.go index 77e6bb9daf..b2f94d32c6 100644 --- a/adapters/mediasquare/utils.go +++ b/adapters/mediasquare/utils.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) var headerList = map[string][]string{ diff --git a/adapters/melozen/melozen.go b/adapters/melozen/melozen.go index d49cc28784..2b9353a253 100644 --- a/adapters/melozen/melozen.go +++ b/adapters/melozen/melozen.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/melozen/melozen_test.go b/adapters/melozen/melozen_test.go index cf6189c6ab..c2db273e18 100644 --- a/adapters/melozen/melozen_test.go +++ b/adapters/melozen/melozen_test.go @@ -3,9 +3,9 @@ package melozen 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/melozen/params_test.go b/adapters/melozen/params_test.go index 42a4b38ec8..19d4d2e243 100644 --- a/adapters/melozen/params_test.go +++ b/adapters/melozen/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) { diff --git a/adapters/metax/metax.go b/adapters/metax/metax.go index 8b19704362..f5e0a3a69f 100644 --- a/adapters/metax/metax.go +++ b/adapters/metax/metax.go @@ -9,13 +9,13 @@ 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/v3/util/ptrutil" + "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" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type adapter struct { diff --git a/adapters/metax/metax_test.go b/adapters/metax/metax_test.go index f4f9d7e496..74399aada1 100644 --- a/adapters/metax/metax_test.go +++ b/adapters/metax/metax_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/adapters/metax/params_test.go b/adapters/metax/params_test.go index 4487c23326..f0ae81cb73 100644 --- a/adapters/metax/params_test.go +++ b/adapters/metax/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" ) // This file actually intends to test static/bidder-params/metax.json diff --git a/adapters/mgid/mgid.go b/adapters/mgid/mgid.go index 68a760a7f5..159475eecc 100644 --- a/adapters/mgid/mgid.go +++ b/adapters/mgid/mgid.go @@ -7,11 +7,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type MgidAdapter struct { diff --git a/adapters/mgid/mgid_test.go b/adapters/mgid/mgid_test.go index 7dc7018b57..50d7792d1b 100644 --- a/adapters/mgid/mgid_test.go +++ b/adapters/mgid/mgid_test.go @@ -3,9 +3,9 @@ package mgid 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) { diff --git a/adapters/mgidX/mgidX.go b/adapters/mgidX/mgidX.go index f952fc27ff..1b123b04d6 100644 --- a/adapters/mgidX/mgidX.go +++ b/adapters/mgidX/mgidX.go @@ -7,10 +7,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/mgidX/mgidX_test.go b/adapters/mgidX/mgidX_test.go index 90ea5c7904..33ea88c0d1 100644 --- a/adapters/mgidX/mgidX_test.go +++ b/adapters/mgidX/mgidX_test.go @@ -3,9 +3,9 @@ package mgidX 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) { diff --git a/adapters/mgidX/params_test.go b/adapters/mgidX/params_test.go index c5246fba4b..0bc39eafa9 100644 --- a/adapters/mgidX/params_test.go +++ b/adapters/mgidX/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) { diff --git a/adapters/minutemedia/minutemedia.go b/adapters/minutemedia/minutemedia.go index f5a212501a..209492527c 100644 --- a/adapters/minutemedia/minutemedia.go +++ b/adapters/minutemedia/minutemedia.go @@ -10,11 +10,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // adapter is a MinuteMedia implementation of the adapters.Bidder interface. diff --git a/adapters/minutemedia/minutemedia_test.go b/adapters/minutemedia/minutemedia_test.go index aa3ce56ca2..577f4388f2 100644 --- a/adapters/minutemedia/minutemedia_test.go +++ b/adapters/minutemedia/minutemedia_test.go @@ -3,9 +3,9 @@ package minutemedia 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" ) const testsDir = "minutemediatest" diff --git a/adapters/missena/missena.go b/adapters/missena/missena.go index ae51ec6274..b620a89972 100644 --- a/adapters/missena/missena.go +++ b/adapters/missena/missena.go @@ -7,13 +7,13 @@ 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/v3/version" + "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" + "github.com/prebid/prebid-server/v4/version" ) type adapter struct { diff --git a/adapters/missena/missena_test.go b/adapters/missena/missena_test.go index 4a858d27c1..e6a4a69038 100644 --- a/adapters/missena/missena_test.go +++ b/adapters/missena/missena_test.go @@ -3,9 +3,9 @@ package missena 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) { diff --git a/adapters/missena/params_test.go b/adapters/missena/params_test.go index 91eca91f92..496a44bf8b 100644 --- a/adapters/missena/params_test.go +++ b/adapters/missena/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) { diff --git a/adapters/mobfoxpb/mobfoxpb.go b/adapters/mobfoxpb/mobfoxpb.go index 538e7f7bce..5f9dff28f7 100644 --- a/adapters/mobfoxpb/mobfoxpb.go +++ b/adapters/mobfoxpb/mobfoxpb.go @@ -8,11 +8,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/mobfoxpb/mobfoxpb_test.go b/adapters/mobfoxpb/mobfoxpb_test.go index cbcfd29ebc..4a36694e02 100644 --- a/adapters/mobfoxpb/mobfoxpb_test.go +++ b/adapters/mobfoxpb/mobfoxpb_test.go @@ -3,9 +3,9 @@ package mobfoxpb 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) { diff --git a/adapters/mobfoxpb/params_test.go b/adapters/mobfoxpb/params_test.go index 52b9ffb627..40553b9461 100644 --- a/adapters/mobfoxpb/params_test.go +++ b/adapters/mobfoxpb/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" ) // TestValidParams makes sure that the mobfoxpb schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/mobilefuse/mobilefuse.go b/adapters/mobilefuse/mobilefuse.go index 88e562b47f..a7f50dc0b0 100644 --- a/adapters/mobilefuse/mobilefuse.go +++ b/adapters/mobilefuse/mobilefuse.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type MobileFuseAdapter struct { diff --git a/adapters/mobilefuse/mobilefuse_test.go b/adapters/mobilefuse/mobilefuse_test.go index e0a2f3dc23..0d05f27fcc 100644 --- a/adapters/mobilefuse/mobilefuse_test.go +++ b/adapters/mobilefuse/mobilefuse_test.go @@ -3,9 +3,9 @@ package mobilefuse 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) { diff --git a/adapters/mobilefuse/params_test.go b/adapters/mobilefuse/params_test.go index e585675457..2ef8686ab0 100644 --- a/adapters/mobilefuse/params_test.go +++ b/adapters/mobilefuse/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(test *testing.T) { diff --git a/adapters/mobkoi/mobkoi.go b/adapters/mobkoi/mobkoi.go index 902616dd3f..b9569fd3fa 100644 --- a/adapters/mobkoi/mobkoi.go +++ b/adapters/mobkoi/mobkoi.go @@ -5,10 +5,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/mobkoi/mobkoi_test.go b/adapters/mobkoi/mobkoi_test.go index 19bcdb8385..6c61fffc71 100644 --- a/adapters/mobkoi/mobkoi_test.go +++ b/adapters/mobkoi/mobkoi_test.go @@ -3,9 +3,9 @@ package mobkoi 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) { diff --git a/adapters/mobkoi/params_test.go b/adapters/mobkoi/params_test.go index ea279629dc..ad34cedadf 100644 --- a/adapters/mobkoi/params_test.go +++ b/adapters/mobkoi/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(test *testing.T) { diff --git a/adapters/motorik/motorik.go b/adapters/motorik/motorik.go index 5256605ec8..4802d19b0e 100644 --- a/adapters/motorik/motorik.go +++ b/adapters/motorik/motorik.go @@ -7,12 +7,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/motorik/motorik_test.go b/adapters/motorik/motorik_test.go index 5d99d05012..9a94bc633a 100644 --- a/adapters/motorik/motorik_test.go +++ b/adapters/motorik/motorik_test.go @@ -3,9 +3,9 @@ package motorik 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/motorik/params_test.go b/adapters/motorik/params_test.go index 9c8dc2f5d1..5a8dc41891 100644 --- a/adapters/motorik/params_test.go +++ b/adapters/motorik/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" ) var validParams = []string{ diff --git a/adapters/msft/models.go b/adapters/msft/models.go index 625251c773..7a3bf291fb 100644 --- a/adapters/msft/models.go +++ b/adapters/msft/models.go @@ -1,7 +1,7 @@ package msft import ( - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type extraAdapterInfo struct { diff --git a/adapters/msft/msft.go b/adapters/msft/msft.go index c7711dace6..8eae4790cc 100644 --- a/adapters/msft/msft.go +++ b/adapters/msft/msft.go @@ -10,12 +10,12 @@ import ( "github.com/buger/jsonparser" "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/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const ( diff --git a/adapters/msft/msft_test.go b/adapters/msft/msft_test.go index b16a8c64b2..6247788282 100644 --- a/adapters/msft/msft_test.go +++ b/adapters/msft/msft_test.go @@ -3,9 +3,9 @@ package msft 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/msft/params_test.go b/adapters/msft/params_test.go index 1046a4a0b2..6c897aafd1 100644 --- a/adapters/msft/params_test.go +++ b/adapters/msft/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" ) // This file tests static/bidder-params/msft.json diff --git a/adapters/nativery/nativery.go b/adapters/nativery/nativery.go index 1cd05aac12..99a0a4ff5c 100644 --- a/adapters/nativery/nativery.go +++ b/adapters/nativery/nativery.go @@ -6,12 +6,12 @@ import ( "net/http" "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/metrics" - "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/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/nativery/nativery_test.go b/adapters/nativery/nativery_test.go index 4875089fea..0c7bdce2d6 100644 --- a/adapters/nativery/nativery_test.go +++ b/adapters/nativery/nativery_test.go @@ -3,9 +3,9 @@ package nativery 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) { diff --git a/adapters/nativery/params_test.go b/adapters/nativery/params_test.go index 557c3e0bb9..79f3cb3d0b 100644 --- a/adapters/nativery/params_test.go +++ b/adapters/nativery/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) { diff --git a/adapters/nativo/nativo.go b/adapters/nativo/nativo.go index 6e595bbff8..ab84e01575 100644 --- a/adapters/nativo/nativo.go +++ b/adapters/nativo/nativo.go @@ -6,9 +6,9 @@ import ( "net/http" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type adapter struct { diff --git a/adapters/nativo/nativo_test.go b/adapters/nativo/nativo_test.go index 87bce3f08d..6318bc0aea 100644 --- a/adapters/nativo/nativo_test.go +++ b/adapters/nativo/nativo_test.go @@ -3,9 +3,9 @@ package nativo 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 TestBidderNativo(t *testing.T) { diff --git a/adapters/nextmillennium/nextmillennium.go b/adapters/nextmillennium/nextmillennium.go index 1b2546b662..c678b39eda 100644 --- a/adapters/nextmillennium/nextmillennium.go +++ b/adapters/nextmillennium/nextmillennium.go @@ -6,12 +6,12 @@ import ( "net/http" "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" - "github.com/prebid/prebid-server/v3/version" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) const NM_ADAPTER_VERSION = "v1.0.1" diff --git a/adapters/nextmillennium/nextmillennium_test.go b/adapters/nextmillennium/nextmillennium_test.go index 1ffe49540b..da32f73484 100644 --- a/adapters/nextmillennium/nextmillennium_test.go +++ b/adapters/nextmillennium/nextmillennium_test.go @@ -3,9 +3,9 @@ package nextmillennium 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/nextmillennium/params_test.go b/adapters/nextmillennium/params_test.go index 3833c474a3..fcfab8e41d 100644 --- a/adapters/nextmillennium/params_test.go +++ b/adapters/nextmillennium/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) { diff --git a/adapters/nexx360/nexx360.go b/adapters/nexx360/nexx360.go index e69b375db2..4d63524ba6 100644 --- a/adapters/nexx360/nexx360.go +++ b/adapters/nexx360/nexx360.go @@ -7,12 +7,12 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/version" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) type adapter struct { diff --git a/adapters/nexx360/nexx360_test.go b/adapters/nexx360/nexx360_test.go index f7a8741f17..e66cc24219 100644 --- a/adapters/nexx360/nexx360_test.go +++ b/adapters/nexx360/nexx360_test.go @@ -3,9 +3,9 @@ package nexx360 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) { diff --git a/adapters/nexx360/params_test.go b/adapters/nexx360/params_test.go index dc21d21134..45b4c38d96 100644 --- a/adapters/nexx360/params_test.go +++ b/adapters/nexx360/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" ) // This file actually intends to test static/bidder-params/nexx360.json diff --git a/adapters/nobid/nobid.go b/adapters/nobid/nobid.go index 811ef3363e..12be203e5c 100644 --- a/adapters/nobid/nobid.go +++ b/adapters/nobid/nobid.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // NoBidAdapter - NoBid Adapter definition diff --git a/adapters/nobid/nobid_test.go b/adapters/nobid/nobid_test.go index 6b4a7346cf..ad117b4c80 100644 --- a/adapters/nobid/nobid_test.go +++ b/adapters/nobid/nobid_test.go @@ -3,9 +3,9 @@ package nobid 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) { diff --git a/adapters/nobid/params_test.go b/adapters/nobid/params_test.go index 375237f344..27acf08d21 100644 --- a/adapters/nobid/params_test.go +++ b/adapters/nobid/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) { diff --git a/adapters/ogury/ogury.go b/adapters/ogury/ogury.go index 1b2293c1bc..a97923da06 100644 --- a/adapters/ogury/ogury.go +++ b/adapters/ogury/ogury.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/ogury/ogury_test.go b/adapters/ogury/ogury_test.go index 504be6ccaa..2c57b27d39 100644 --- a/adapters/ogury/ogury_test.go +++ b/adapters/ogury/ogury_test.go @@ -3,9 +3,9 @@ package ogury 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) { diff --git a/adapters/ogury/param_test.go b/adapters/ogury/param_test.go index f4c7c83445..b48b22cb33 100644 --- a/adapters/ogury/param_test.go +++ b/adapters/ogury/param_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) { diff --git a/adapters/oms/oms.go b/adapters/oms/oms.go index 3ea5bd3284..3e4e8ff392 100644 --- a/adapters/oms/oms.go +++ b/adapters/oms/oms.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/oms/oms_test.go b/adapters/oms/oms_test.go index e0555b3c75..d0d14fe1eb 100644 --- a/adapters/oms/oms_test.go +++ b/adapters/oms/oms_test.go @@ -3,9 +3,9 @@ package oms 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) { diff --git a/adapters/oms/params_test.go b/adapters/oms/params_test.go index ed4113d423..300c2058d0 100644 --- a/adapters/oms/params_test.go +++ b/adapters/oms/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" ) // This file actually intends to test static/bidder-params/oms.json diff --git a/adapters/onetag/onetag.go b/adapters/onetag/onetag.go index d1b2e6238e..efa38c631e 100644 --- a/adapters/onetag/onetag.go +++ b/adapters/onetag/onetag.go @@ -7,12 +7,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/onetag/onetag_test.go b/adapters/onetag/onetag_test.go index 23a2871758..f7c64ef3f9 100644 --- a/adapters/onetag/onetag_test.go +++ b/adapters/onetag/onetag_test.go @@ -3,9 +3,9 @@ package onetag 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/onetag/params_test.go b/adapters/onetag/params_test.go index 6ccf060696..3d6021a5dc 100644 --- a/adapters/onetag/params_test.go +++ b/adapters/onetag/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) { diff --git a/adapters/openweb/openweb.go b/adapters/openweb/openweb.go index 7a9914b272..5d8e770cf3 100644 --- a/adapters/openweb/openweb.go +++ b/adapters/openweb/openweb.go @@ -10,11 +10,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/openweb/openweb_test.go b/adapters/openweb/openweb_test.go index a08788e7db..51b2305c6f 100644 --- a/adapters/openweb/openweb_test.go +++ b/adapters/openweb/openweb_test.go @@ -3,9 +3,9 @@ package openweb 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) { diff --git a/adapters/openweb/params_test.go b/adapters/openweb/params_test.go index 73fb20a7e9..622816033c 100644 --- a/adapters/openweb/params_test.go +++ b/adapters/openweb/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" ) // This file actually intends to test static/bidder-params/openweb.json diff --git a/adapters/openx/openx.go b/adapters/openx/openx.go index 992baa0cdc..5148ffde25 100644 --- a/adapters/openx/openx.go +++ b/adapters/openx/openx.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const hbconfig = "hb_pbs_1.0.0" diff --git a/adapters/openx/openx_test.go b/adapters/openx/openx_test.go index fdfb37cc4a..dd320b717f 100644 --- a/adapters/openx/openx_test.go +++ b/adapters/openx/openx_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/openx/params_test.go b/adapters/openx/params_test.go index 0becd9b206..1fc71fce7e 100644 --- a/adapters/openx/params_test.go +++ b/adapters/openx/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" ) // This file actually intends to test static/bidder-params/openx.json diff --git a/adapters/operaads/operaads.go b/adapters/operaads/operaads.go index 47c372beca..448c4843a6 100644 --- a/adapters/operaads/operaads.go +++ b/adapters/operaads/operaads.go @@ -8,13 +8,13 @@ import ( "strings" "text/template" - "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/v3/util/ptrutil" + "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" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/operaads/operaads_test.go b/adapters/operaads/operaads_test.go index 8614e77e7e..b5e21bd8cd 100644 --- a/adapters/operaads/operaads_test.go +++ b/adapters/operaads/operaads_test.go @@ -3,9 +3,9 @@ package operaads 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) { diff --git a/adapters/operaads/params_test.go b/adapters/operaads/params_test.go index b845fde89b..a20d374942 100644 --- a/adapters/operaads/params_test.go +++ b/adapters/operaads/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" ) // This file actually intends to test static/bidder-params/operaads.json diff --git a/adapters/optidigital/optidigital.go b/adapters/optidigital/optidigital.go index 89e2474d97..a59cd2a73a 100644 --- a/adapters/optidigital/optidigital.go +++ b/adapters/optidigital/optidigital.go @@ -4,11 +4,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/optidigital/optidigital_test.go b/adapters/optidigital/optidigital_test.go index dda8b09b54..d89bb92e0c 100644 --- a/adapters/optidigital/optidigital_test.go +++ b/adapters/optidigital/optidigital_test.go @@ -3,9 +3,9 @@ package optidigital 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) { diff --git a/adapters/optidigital/params_test.go b/adapters/optidigital/params_test.go index 5c29d9796d..cb5c9329f2 100644 --- a/adapters/optidigital/params_test.go +++ b/adapters/optidigital/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" ) // This file actually intends to test static/bidder-params/optidigital.json diff --git a/adapters/oraki/oraki.go b/adapters/oraki/oraki.go index db6876f2e0..49a970d934 100644 --- a/adapters/oraki/oraki.go +++ b/adapters/oraki/oraki.go @@ -6,10 +6,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/oraki/oraki_test.go b/adapters/oraki/oraki_test.go index 753357c29f..e37922fb1b 100644 --- a/adapters/oraki/oraki_test.go +++ b/adapters/oraki/oraki_test.go @@ -3,9 +3,9 @@ package oraki 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) { diff --git a/adapters/oraki/params_test.go b/adapters/oraki/params_test.go index 24fc6ea29e..3e8ca92e90 100644 --- a/adapters/oraki/params_test.go +++ b/adapters/oraki/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) { diff --git a/adapters/orbidder/orbidder.go b/adapters/orbidder/orbidder.go index b2f6705273..980ffdde3e 100644 --- a/adapters/orbidder/orbidder.go +++ b/adapters/orbidder/orbidder.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type OrbidderAdapter struct { diff --git a/adapters/orbidder/orbidder_test.go b/adapters/orbidder/orbidder_test.go index ce26bdd7f2..1b29f988fb 100644 --- a/adapters/orbidder/orbidder_test.go +++ b/adapters/orbidder/orbidder_test.go @@ -8,10 +8,10 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/mock" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/orbidder/params_test.go b/adapters/orbidder/params_test.go index bb557faa2c..9f8d316b18 100644 --- a/adapters/orbidder/params_test.go +++ b/adapters/orbidder/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" ) // This file actually intends to test static/bidder-params/orbidder.json diff --git a/adapters/outbrain/outbrain.go b/adapters/outbrain/outbrain.go index 612a9a0cbe..dfcc2ec378 100644 --- a/adapters/outbrain/outbrain.go +++ b/adapters/outbrain/outbrain.go @@ -8,11 +8,11 @@ import ( "github.com/prebid/openrtb/v20/native1" nativeResponse "github.com/prebid/openrtb/v20/native1/response" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/outbrain/outbrain_test.go b/adapters/outbrain/outbrain_test.go index 1e1fc1e803..84b347df51 100644 --- a/adapters/outbrain/outbrain_test.go +++ b/adapters/outbrain/outbrain_test.go @@ -3,9 +3,9 @@ package outbrain 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) { diff --git a/adapters/outbrain/params_test.go b/adapters/outbrain/params_test.go index e6d76d9472..9df86a4e15 100644 --- a/adapters/outbrain/params_test.go +++ b/adapters/outbrain/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) { diff --git a/adapters/ownadx/ownadx.go b/adapters/ownadx/ownadx.go index 737adfa30d..f01048d812 100644 --- a/adapters/ownadx/ownadx.go +++ b/adapters/ownadx/ownadx.go @@ -7,12 +7,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/ownadx/ownadx_test.go b/adapters/ownadx/ownadx_test.go index 6921e1ba12..6f979f185c 100644 --- a/adapters/ownadx/ownadx_test.go +++ b/adapters/ownadx/ownadx_test.go @@ -3,9 +3,9 @@ package ownadx 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/pangle/pangle.go b/adapters/pangle/pangle.go index a86052d649..76ad2cc8b6 100644 --- a/adapters/pangle/pangle.go +++ b/adapters/pangle/pangle.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/pangle/pangle_test.go b/adapters/pangle/pangle_test.go index 2143d4f90a..5e52025f02 100644 --- a/adapters/pangle/pangle_test.go +++ b/adapters/pangle/pangle_test.go @@ -3,9 +3,9 @@ package pangle 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) { diff --git a/adapters/pangle/param_test.go b/adapters/pangle/param_test.go index 57acfb0609..57adb0d8f1 100644 --- a/adapters/pangle/param_test.go +++ b/adapters/pangle/param_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" ) var validParams = []string{ diff --git a/adapters/pgamssp/params_test.go b/adapters/pgamssp/params_test.go index ec95d47e5f..fd8962b04e 100644 --- a/adapters/pgamssp/params_test.go +++ b/adapters/pgamssp/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) { diff --git a/adapters/pgamssp/pgamssp.go b/adapters/pgamssp/pgamssp.go index 6ddf21159e..a74719d08c 100644 --- a/adapters/pgamssp/pgamssp.go +++ b/adapters/pgamssp/pgamssp.go @@ -7,10 +7,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/pgamssp/pgamssp_test.go b/adapters/pgamssp/pgamssp_test.go index 450eb0f0b5..691e8cbb8a 100644 --- a/adapters/pgamssp/pgamssp_test.go +++ b/adapters/pgamssp/pgamssp_test.go @@ -3,9 +3,9 @@ package pgamssp 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) { diff --git a/adapters/playdigo/params_test.go b/adapters/playdigo/params_test.go index cb0fa0c681..f586019b45 100644 --- a/adapters/playdigo/params_test.go +++ b/adapters/playdigo/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) { diff --git a/adapters/playdigo/playdigo.go b/adapters/playdigo/playdigo.go index fe0091e2cb..578e39ae7b 100644 --- a/adapters/playdigo/playdigo.go +++ b/adapters/playdigo/playdigo.go @@ -7,10 +7,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/playdigo/playdigo_test.go b/adapters/playdigo/playdigo_test.go index 275924f193..0318659595 100644 --- a/adapters/playdigo/playdigo_test.go +++ b/adapters/playdigo/playdigo_test.go @@ -3,9 +3,9 @@ package playdigo 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) { diff --git a/adapters/pubmatic/params_test.go b/adapters/pubmatic/params_test.go index 531416f187..5ca06fdaf9 100644 --- a/adapters/pubmatic/params_test.go +++ b/adapters/pubmatic/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" ) // This file actually intends to test static/bidder-params/pubmatic.json diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index e35229143c..ebc6634090 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -9,12 +9,12 @@ import ( "strconv" "strings" - "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go index ac1e645c19..de7afcd4d4 100644 --- a/adapters/pubmatic/pubmatic_test.go +++ b/adapters/pubmatic/pubmatic_test.go @@ -8,11 +8,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "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/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/pubnative/pubnative.go b/adapters/pubnative/pubnative.go index 7c77aeefc9..b30912d257 100644 --- a/adapters/pubnative/pubnative.go +++ b/adapters/pubnative/pubnative.go @@ -8,12 +8,12 @@ import ( "strconv" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type PubnativeAdapter struct { diff --git a/adapters/pubnative/pubnative_test.go b/adapters/pubnative/pubnative_test.go index dfc065b716..c4e8613b8d 100644 --- a/adapters/pubnative/pubnative_test.go +++ b/adapters/pubnative/pubnative_test.go @@ -3,9 +3,9 @@ package pubnative 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) { diff --git a/adapters/pubrise/params_test.go b/adapters/pubrise/params_test.go index 97ee8ebc5c..4422295bd7 100644 --- a/adapters/pubrise/params_test.go +++ b/adapters/pubrise/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) { diff --git a/adapters/pubrise/pubrise.go b/adapters/pubrise/pubrise.go index 80168f9725..2c4b11e5c3 100644 --- a/adapters/pubrise/pubrise.go +++ b/adapters/pubrise/pubrise.go @@ -7,10 +7,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/pubrise/pubrise_test.go b/adapters/pubrise/pubrise_test.go index 9f4f2124ab..abccfafddc 100644 --- a/adapters/pubrise/pubrise_test.go +++ b/adapters/pubrise/pubrise_test.go @@ -3,9 +3,9 @@ package pubrise 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) { diff --git a/adapters/pulsepoint/params_test.go b/adapters/pulsepoint/params_test.go index 4359c4115a..56cf4139c0 100644 --- a/adapters/pulsepoint/params_test.go +++ b/adapters/pulsepoint/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) { diff --git a/adapters/pulsepoint/pulsepoint.go b/adapters/pulsepoint/pulsepoint.go index 2f750e9f85..11dd7533a4 100644 --- a/adapters/pulsepoint/pulsepoint.go +++ b/adapters/pulsepoint/pulsepoint.go @@ -7,11 +7,11 @@ import ( "net/http" "strconv" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/pulsepoint/pulsepoint_test.go b/adapters/pulsepoint/pulsepoint_test.go index be9fff83a6..fb766aab8c 100644 --- a/adapters/pulsepoint/pulsepoint_test.go +++ b/adapters/pulsepoint/pulsepoint_test.go @@ -3,9 +3,9 @@ package pulsepoint 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) { diff --git a/adapters/pwbid/params_test.go b/adapters/pwbid/params_test.go index 52f06e0257..a57cf6baea 100644 --- a/adapters/pwbid/params_test.go +++ b/adapters/pwbid/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) { diff --git a/adapters/pwbid/pwbid.go b/adapters/pwbid/pwbid.go index 7e03185f2c..6cd6b9ea6e 100644 --- a/adapters/pwbid/pwbid.go +++ b/adapters/pwbid/pwbid.go @@ -5,11 +5,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/pwbid/pwbid_test.go b/adapters/pwbid/pwbid_test.go index cb028a19f6..3a9e76e2b6 100644 --- a/adapters/pwbid/pwbid_test.go +++ b/adapters/pwbid/pwbid_test.go @@ -3,9 +3,9 @@ package pwbid 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) { diff --git a/adapters/qt/params_test.go b/adapters/qt/params_test.go index 5c8d3253be..0b46b55067 100644 --- a/adapters/qt/params_test.go +++ b/adapters/qt/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) { diff --git a/adapters/qt/qt.go b/adapters/qt/qt.go index a7c5d53c5a..1a1a96acbe 100644 --- a/adapters/qt/qt.go +++ b/adapters/qt/qt.go @@ -6,10 +6,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/qt/qt_test.go b/adapters/qt/qt_test.go index f85adbaf18..3da46eb223 100644 --- a/adapters/qt/qt_test.go +++ b/adapters/qt/qt_test.go @@ -3,9 +3,9 @@ package qt 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) { diff --git a/adapters/readpeak/params_test.go b/adapters/readpeak/params_test.go index 772855e425..d71396eb35 100644 --- a/adapters/readpeak/params_test.go +++ b/adapters/readpeak/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) { diff --git a/adapters/readpeak/readpeak.go b/adapters/readpeak/readpeak.go index 7049dace48..5aaf8c9d80 100644 --- a/adapters/readpeak/readpeak.go +++ b/adapters/readpeak/readpeak.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/readpeak/readpeak_test.go b/adapters/readpeak/readpeak_test.go index 8c8e8e27be..9f4feb20c1 100644 --- a/adapters/readpeak/readpeak_test.go +++ b/adapters/readpeak/readpeak_test.go @@ -3,9 +3,9 @@ package readpeak 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) { diff --git a/adapters/rediads/params_test.go b/adapters/rediads/params_test.go index af69698237..d191206823 100644 --- a/adapters/rediads/params_test.go +++ b/adapters/rediads/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) { diff --git a/adapters/rediads/rediads.go b/adapters/rediads/rediads.go index cfa60eacf6..349504219b 100644 --- a/adapters/rediads/rediads.go +++ b/adapters/rediads/rediads.go @@ -7,11 +7,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/rediads/rediads_test.go b/adapters/rediads/rediads_test.go index b5e935b680..ec263d8324 100644 --- a/adapters/rediads/rediads_test.go +++ b/adapters/rediads/rediads_test.go @@ -3,9 +3,9 @@ package rediads 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) { diff --git a/adapters/relevantdigital/params_test.go b/adapters/relevantdigital/params_test.go index 987dfd6e58..835e1e77c8 100644 --- a/adapters/relevantdigital/params_test.go +++ b/adapters/relevantdigital/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) { diff --git a/adapters/relevantdigital/relevantdigital.go b/adapters/relevantdigital/relevantdigital.go index 702dca6b27..3286b49714 100644 --- a/adapters/relevantdigital/relevantdigital.go +++ b/adapters/relevantdigital/relevantdigital.go @@ -10,12 +10,12 @@ import ( "github.com/buger/jsonparser" "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" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/adapters/relevantdigital/relevantdigital_test.go b/adapters/relevantdigital/relevantdigital_test.go index 31e6b370d8..8859a27d37 100644 --- a/adapters/relevantdigital/relevantdigital_test.go +++ b/adapters/relevantdigital/relevantdigital_test.go @@ -3,9 +3,9 @@ package relevantdigital 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/resetdigital/params_test.go b/adapters/resetdigital/params_test.go index 5b8c776d9d..f82b10855e 100644 --- a/adapters/resetdigital/params_test.go +++ b/adapters/resetdigital/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) { diff --git a/adapters/resetdigital/resetdigital.go b/adapters/resetdigital/resetdigital.go index 54b5f38daa..40050400ea 100644 --- a/adapters/resetdigital/resetdigital.go +++ b/adapters/resetdigital/resetdigital.go @@ -7,10 +7,10 @@ import ( "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/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "golang.org/x/text/currency" ) diff --git a/adapters/resetdigital/resetdigital_test.go b/adapters/resetdigital/resetdigital_test.go index 0bd5a35627..dd33c8bdeb 100644 --- a/adapters/resetdigital/resetdigital_test.go +++ b/adapters/resetdigital/resetdigital_test.go @@ -6,11 +6,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "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/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/response.go b/adapters/response.go index ec02513ca6..6c3c6a8237 100644 --- a/adapters/response.go +++ b/adapters/response.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) func CheckResponseStatusCodeForErrors(response *ResponseData) error { diff --git a/adapters/response_test.go b/adapters/response_test.go index 28fbefdf52..70106756b4 100644 --- a/adapters/response_test.go +++ b/adapters/response_test.go @@ -3,7 +3,7 @@ package adapters import ( "testing" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" "github.com/stretchr/testify/assert" ) diff --git a/adapters/revcontent/revcontent.go b/adapters/revcontent/revcontent.go index 881b1d4916..7793e6fdd1 100644 --- a/adapters/revcontent/revcontent.go +++ b/adapters/revcontent/revcontent.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/revcontent/revcontent_test.go b/adapters/revcontent/revcontent_test.go index 35e6970c7f..5b266e2fcd 100644 --- a/adapters/revcontent/revcontent_test.go +++ b/adapters/revcontent/revcontent_test.go @@ -3,9 +3,9 @@ package revcontent 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) { diff --git a/adapters/richaudience/params_test.go b/adapters/richaudience/params_test.go index 8f5b2e244b..f0bf685372 100644 --- a/adapters/richaudience/params_test.go +++ b/adapters/richaudience/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) { diff --git a/adapters/richaudience/richaudience.go b/adapters/richaudience/richaudience.go index 969fd312c9..0d8b5d2e29 100644 --- a/adapters/richaudience/richaudience.go +++ b/adapters/richaudience/richaudience.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/richaudience/richaudience_test.go b/adapters/richaudience/richaudience_test.go index 342301f808..a55e5225d1 100644 --- a/adapters/richaudience/richaudience_test.go +++ b/adapters/richaudience/richaudience_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/rise/rise.go b/adapters/rise/rise.go index 9a438f6dac..d9d9c2a4bc 100644 --- a/adapters/rise/rise.go +++ b/adapters/rise/rise.go @@ -9,10 +9,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // adapter is a Rise implementation of the adapters.Bidder interface. diff --git a/adapters/rise/rise_test.go b/adapters/rise/rise_test.go index d7235a7f3f..8d10cedb95 100644 --- a/adapters/rise/rise_test.go +++ b/adapters/rise/rise_test.go @@ -3,9 +3,9 @@ package rise 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" ) const testsDir = "risetest" diff --git a/adapters/roulax/roulax.go b/adapters/roulax/roulax.go index 9923836908..c5af6833fc 100644 --- a/adapters/roulax/roulax.go +++ b/adapters/roulax/roulax.go @@ -7,11 +7,11 @@ 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/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/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/roulax/roulax_test.go b/adapters/roulax/roulax_test.go index 3bd03bbbf3..67744873da 100644 --- a/adapters/roulax/roulax_test.go +++ b/adapters/roulax/roulax_test.go @@ -3,9 +3,9 @@ package roulax 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" ) const testsDir = "roulaxtest" diff --git a/adapters/rtbhouse/rtbhouse.go b/adapters/rtbhouse/rtbhouse.go index c6445f1f15..757780b95d 100644 --- a/adapters/rtbhouse/rtbhouse.go +++ b/adapters/rtbhouse/rtbhouse.go @@ -10,11 +10,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/rtbhouse/rtbhouse_test.go b/adapters/rtbhouse/rtbhouse_test.go index c7189cffc9..8dde82f949 100644 --- a/adapters/rtbhouse/rtbhouse_test.go +++ b/adapters/rtbhouse/rtbhouse_test.go @@ -3,9 +3,9 @@ package rtbhouse 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" ) const testsDir = "rtbhousetest" diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go index b0a694905a..efcde7037c 100644 --- a/adapters/rubicon/rubicon.go +++ b/adapters/rubicon/rubicon.go @@ -8,14 +8,14 @@ import ( "strconv" "strings" - "github.com/prebid/prebid-server/v3/version" - - "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" - "github.com/prebid/prebid-server/v3/util/maputil" + "github.com/prebid/prebid-server/v4/version" + + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/maputil" "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go index 3e26e2db12..fe9f079c00 100644 --- a/adapters/rubicon/rubicon_test.go +++ b/adapters/rubicon/rubicon_test.go @@ -8,12 +8,12 @@ import ( "strconv" "testing" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "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/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/adcom1" diff --git a/adapters/sa_lunamedia/params_test.go b/adapters/sa_lunamedia/params_test.go index 640af6ceb3..1ad6ccf3fd 100644 --- a/adapters/sa_lunamedia/params_test.go +++ b/adapters/sa_lunamedia/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" ) var validParams = []string{ diff --git a/adapters/sa_lunamedia/salunamedia.go b/adapters/sa_lunamedia/salunamedia.go index b75ccd9f8a..69b19d9fcd 100644 --- a/adapters/sa_lunamedia/salunamedia.go +++ b/adapters/sa_lunamedia/salunamedia.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/sa_lunamedia/salunamedia_test.go b/adapters/sa_lunamedia/salunamedia_test.go index 3247bb0a57..953bbca6e0 100644 --- a/adapters/sa_lunamedia/salunamedia_test.go +++ b/adapters/sa_lunamedia/salunamedia_test.go @@ -3,9 +3,9 @@ package salunamedia 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/seedingAlliance/params_test.go b/adapters/seedingAlliance/params_test.go index 56433b003c..77088c077d 100644 --- a/adapters/seedingAlliance/params_test.go +++ b/adapters/seedingAlliance/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) { diff --git a/adapters/seedingAlliance/seedingAlliance.go b/adapters/seedingAlliance/seedingAlliance.go index 1e23d4e25a..bc367da19e 100644 --- a/adapters/seedingAlliance/seedingAlliance.go +++ b/adapters/seedingAlliance/seedingAlliance.go @@ -9,12 +9,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/seedingAlliance/seedingAlliance_test.go b/adapters/seedingAlliance/seedingAlliance_test.go index b432d0577f..f5721683d7 100644 --- a/adapters/seedingAlliance/seedingAlliance_test.go +++ b/adapters/seedingAlliance/seedingAlliance_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/seedtag/params_test.go b/adapters/seedtag/params_test.go index b93be85dfb..2c39237739 100644 --- a/adapters/seedtag/params_test.go +++ b/adapters/seedtag/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) { diff --git a/adapters/seedtag/seedtag.go b/adapters/seedtag/seedtag.go index 11e21699c2..e48886b875 100644 --- a/adapters/seedtag/seedtag.go +++ b/adapters/seedtag/seedtag.go @@ -6,10 +6,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/seedtag/seedtag_test.go b/adapters/seedtag/seedtag_test.go index bdfbc7725e..4629793ffd 100644 --- a/adapters/seedtag/seedtag_test.go +++ b/adapters/seedtag/seedtag_test.go @@ -3,9 +3,9 @@ package seedtag 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) { diff --git a/adapters/sharethrough/params_test.go b/adapters/sharethrough/params_test.go index a7011ab376..03c60cec38 100644 --- a/adapters/sharethrough/params_test.go +++ b/adapters/sharethrough/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) { diff --git a/adapters/sharethrough/sharethrough.go b/adapters/sharethrough/sharethrough.go index cf5c65a736..7663122788 100644 --- a/adapters/sharethrough/sharethrough.go +++ b/adapters/sharethrough/sharethrough.go @@ -7,12 +7,12 @@ import ( "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" - "github.com/prebid/prebid-server/v3/version" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) var adapterVersion = "10.0" diff --git a/adapters/sharethrough/sharethrough_test.go b/adapters/sharethrough/sharethrough_test.go index 6ca7d9c7ef..fd2c5d12ed 100644 --- a/adapters/sharethrough/sharethrough_test.go +++ b/adapters/sharethrough/sharethrough_test.go @@ -3,9 +3,9 @@ package sharethrough 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) { diff --git a/adapters/showheroes/params_test.go b/adapters/showheroes/params_test.go index a22693f81a..857a9db650 100644 --- a/adapters/showheroes/params_test.go +++ b/adapters/showheroes/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) { diff --git a/adapters/showheroes/showheroes.go b/adapters/showheroes/showheroes.go index f04adc100d..c2c27b64b1 100644 --- a/adapters/showheroes/showheroes.go +++ b/adapters/showheroes/showheroes.go @@ -6,12 +6,12 @@ import ( "net/http" "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" - "github.com/prebid/prebid-server/v3/version" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) type adapter struct { diff --git a/adapters/showheroes/showheroes_test.go b/adapters/showheroes/showheroes_test.go index 64f8e62f2f..ce82c89255 100644 --- a/adapters/showheroes/showheroes_test.go +++ b/adapters/showheroes/showheroes_test.go @@ -3,9 +3,9 @@ package showheroes 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) { diff --git a/adapters/silvermob/params_test.go b/adapters/silvermob/params_test.go index 9dc9a34eb6..c59190d561 100644 --- a/adapters/silvermob/params_test.go +++ b/adapters/silvermob/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" ) // TestValidParams makes sure that the silvermob schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/silvermob/silvermob.go b/adapters/silvermob/silvermob.go index b51207f13c..062264e4c6 100644 --- a/adapters/silvermob/silvermob.go +++ b/adapters/silvermob/silvermob.go @@ -7,12 +7,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 SilverMobAdapter struct { diff --git a/adapters/silvermob/silvermob_test.go b/adapters/silvermob/silvermob_test.go index 991a758b4e..217dfb7db2 100644 --- a/adapters/silvermob/silvermob_test.go +++ b/adapters/silvermob/silvermob_test.go @@ -3,9 +3,9 @@ package silvermob 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/silverpush/params_test.go b/adapters/silverpush/params_test.go index d98f413a71..721fd69f56 100644 --- a/adapters/silverpush/params_test.go +++ b/adapters/silverpush/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" ) // This file intends to test static/bidder-params/silverpush.json diff --git a/adapters/silverpush/silverpush.go b/adapters/silverpush/silverpush.go index 049b0d5a93..f5b9ac0588 100644 --- a/adapters/silverpush/silverpush.go +++ b/adapters/silverpush/silverpush.go @@ -6,12 +6,12 @@ import ( "net/http" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const ( diff --git a/adapters/silverpush/silverpush_test.go b/adapters/silverpush/silverpush_test.go index f953584f0b..cfb7d296f4 100644 --- a/adapters/silverpush/silverpush_test.go +++ b/adapters/silverpush/silverpush_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/smaato/native.go b/adapters/smaato/native.go index 2cbcae471c..ce73d3d73b 100644 --- a/adapters/smaato/native.go +++ b/adapters/smaato/native.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type nativeAd struct { diff --git a/adapters/smaato/params_test.go b/adapters/smaato/params_test.go index 7acb42c696..99aea5af5a 100644 --- a/adapters/smaato/params_test.go +++ b/adapters/smaato/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" ) // This file intends to test static/bidder-params/smaato.json diff --git a/adapters/smaato/smaato.go b/adapters/smaato/smaato.go index 34800102b8..c782e7fa18 100644 --- a/adapters/smaato/smaato.go +++ b/adapters/smaato/smaato.go @@ -9,13 +9,13 @@ import ( "github.com/buger/jsonparser" "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/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/timeutil" + "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/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) const clientVersion = "prebid_server_1.2" diff --git a/adapters/smaato/smaato_test.go b/adapters/smaato/smaato_test.go index 311724ecd8..bc1d3497af 100644 --- a/adapters/smaato/smaato_test.go +++ b/adapters/smaato/smaato_test.go @@ -10,11 +10,11 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" - "github.com/prebid/prebid-server/v3/adapters" - "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/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/smartadserver/params_test.go b/adapters/smartadserver/params_test.go index fb71edb414..46266e4be8 100644 --- a/adapters/smartadserver/params_test.go +++ b/adapters/smartadserver/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" ) // This file actually intends to test static/bidder-params/smartadserver.json diff --git a/adapters/smartadserver/smartadserver.go b/adapters/smartadserver/smartadserver.go index 1dc801a90d..464084fd61 100644 --- a/adapters/smartadserver/smartadserver.go +++ b/adapters/smartadserver/smartadserver.go @@ -9,11 +9,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type SmartAdserverAdapter struct { diff --git a/adapters/smartadserver/smartadserver_test.go b/adapters/smartadserver/smartadserver_test.go index 51b1fb0914..bb90a4877b 100644 --- a/adapters/smartadserver/smartadserver_test.go +++ b/adapters/smartadserver/smartadserver_test.go @@ -3,9 +3,9 @@ package smartadserver 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) { diff --git a/adapters/smarthub/params_test.go b/adapters/smarthub/params_test.go index 18616abd0f..5a2371f8e8 100644 --- a/adapters/smarthub/params_test.go +++ b/adapters/smarthub/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" ) var validParams = []string{ diff --git a/adapters/smarthub/smarthub.go b/adapters/smarthub/smarthub.go index 7048bb0cc0..733813bd82 100644 --- a/adapters/smarthub/smarthub.go +++ b/adapters/smarthub/smarthub.go @@ -7,12 +7,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" ) const ( diff --git a/adapters/smarthub/smarthub_test.go b/adapters/smarthub/smarthub_test.go index bee9c04aa8..bb88ab1312 100644 --- a/adapters/smarthub/smarthub_test.go +++ b/adapters/smarthub/smarthub_test.go @@ -3,9 +3,9 @@ package smarthub 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/smartrtb/smartrtb.go b/adapters/smartrtb/smartrtb.go index 68fd9bfccb..2e498c57d7 100644 --- a/adapters/smartrtb/smartrtb.go +++ b/adapters/smartrtb/smartrtb.go @@ -7,12 +7,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" ) // Base adapter structure. diff --git a/adapters/smartrtb/smartrtb_test.go b/adapters/smartrtb/smartrtb_test.go index 060323a7ac..5e1fd42a29 100644 --- a/adapters/smartrtb/smartrtb_test.go +++ b/adapters/smartrtb/smartrtb_test.go @@ -3,9 +3,9 @@ package smartrtb 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/smartx/params_test.go b/adapters/smartx/params_test.go index 837c63568a..904586b782 100644 --- a/adapters/smartx/params_test.go +++ b/adapters/smartx/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" ) var validParams = []string{ diff --git a/adapters/smartx/smartx.go b/adapters/smartx/smartx.go index 154f511f03..8a15bb6268 100644 --- a/adapters/smartx/smartx.go +++ b/adapters/smartx/smartx.go @@ -7,10 +7,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/smartx/smartx_test.go b/adapters/smartx/smartx_test.go index 6d25752865..e04f4aa7aa 100644 --- a/adapters/smartx/smartx_test.go +++ b/adapters/smartx/smartx_test.go @@ -3,9 +3,9 @@ package smartx 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" ) const testsDir = "smartxtest" diff --git a/adapters/smartyads/params_test.go b/adapters/smartyads/params_test.go index ed49894629..f379c68f36 100644 --- a/adapters/smartyads/params_test.go +++ b/adapters/smartyads/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" ) var validParams = []string{ diff --git a/adapters/smartyads/smartyads.go b/adapters/smartyads/smartyads.go index 3a07edaf62..9970b3af73 100644 --- a/adapters/smartyads/smartyads.go +++ b/adapters/smartyads/smartyads.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 SmartyAdsAdapter struct { diff --git a/adapters/smartyads/smartyads_test.go b/adapters/smartyads/smartyads_test.go index 330f3900a0..9b7ada132b 100644 --- a/adapters/smartyads/smartyads_test.go +++ b/adapters/smartyads/smartyads_test.go @@ -3,9 +3,9 @@ package smartyads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/smilewanted/params_test.go b/adapters/smilewanted/params_test.go index 78a29dc046..cfca29976f 100644 --- a/adapters/smilewanted/params_test.go +++ b/adapters/smilewanted/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" ) // This file actually intends to test static/bidder-params/smilewanted.json diff --git a/adapters/smilewanted/smilewanted.go b/adapters/smilewanted/smilewanted.go index 3a8efdf0bb..453c2ecb20 100644 --- a/adapters/smilewanted/smilewanted.go +++ b/adapters/smilewanted/smilewanted.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/smilewanted/smilewanted_test.go b/adapters/smilewanted/smilewanted_test.go index 8e291eb505..43dc10a7cc 100644 --- a/adapters/smilewanted/smilewanted_test.go +++ b/adapters/smilewanted/smilewanted_test.go @@ -7,10 +7,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/smoot/params_test.go b/adapters/smoot/params_test.go index ef0ec2149b..259e97308d 100644 --- a/adapters/smoot/params_test.go +++ b/adapters/smoot/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) { diff --git a/adapters/smoot/smoot.go b/adapters/smoot/smoot.go index e23c2de602..9a0df2b4a6 100644 --- a/adapters/smoot/smoot.go +++ b/adapters/smoot/smoot.go @@ -6,10 +6,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/smoot/smoot_test.go b/adapters/smoot/smoot_test.go index 46c6586241..7e4d67fd0e 100644 --- a/adapters/smoot/smoot_test.go +++ b/adapters/smoot/smoot_test.go @@ -3,9 +3,9 @@ package smoot 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) { diff --git a/adapters/smrtconnect/smrtconnect.go b/adapters/smrtconnect/smrtconnect.go index 4ecde49cea..b462b460f0 100644 --- a/adapters/smrtconnect/smrtconnect.go +++ b/adapters/smrtconnect/smrtconnect.go @@ -6,12 +6,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/smrtconnect/smrtconnect_test.go b/adapters/smrtconnect/smrtconnect_test.go index 2b020c1e3a..f715f81411 100644 --- a/adapters/smrtconnect/smrtconnect_test.go +++ b/adapters/smrtconnect/smrtconnect_test.go @@ -3,9 +3,9 @@ package smrtconnect 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/sonobi/params_test.go b/adapters/sonobi/params_test.go index 7ffff8ffdd..eae150661f 100644 --- a/adapters/sonobi/params_test.go +++ b/adapters/sonobi/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" ) // This file actually intends to test static/bidder-params/sonobi.json diff --git a/adapters/sonobi/sonobi.go b/adapters/sonobi/sonobi.go index cf00595c6b..b4adb57e17 100644 --- a/adapters/sonobi/sonobi.go +++ b/adapters/sonobi/sonobi.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // SonobiAdapter - Sonobi SonobiAdapter definition diff --git a/adapters/sonobi/sonobi_test.go b/adapters/sonobi/sonobi_test.go index aa9f44ed7a..35fc29b8f8 100644 --- a/adapters/sonobi/sonobi_test.go +++ b/adapters/sonobi/sonobi_test.go @@ -3,9 +3,9 @@ package sonobi 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) { diff --git a/adapters/sovrn/params_test.go b/adapters/sovrn/params_test.go index 021043c1c6..873ec63a1e 100644 --- a/adapters/sovrn/params_test.go +++ b/adapters/sovrn/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) { diff --git a/adapters/sovrn/sovrn.go b/adapters/sovrn/sovrn.go index 8276c07045..25bbced73f 100644 --- a/adapters/sovrn/sovrn.go +++ b/adapters/sovrn/sovrn.go @@ -8,11 +8,11 @@ import ( "strconv" "strings" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/sovrn/sovrn_test.go b/adapters/sovrn/sovrn_test.go index f2d61d166e..12545b3f6f 100644 --- a/adapters/sovrn/sovrn_test.go +++ b/adapters/sovrn/sovrn_test.go @@ -3,9 +3,9 @@ package sovrn 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) { diff --git a/adapters/sovrnXsp/params_test.go b/adapters/sovrnXsp/params_test.go index 91d31ec54d..2c7270420f 100644 --- a/adapters/sovrnXsp/params_test.go +++ b/adapters/sovrnXsp/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) { diff --git a/adapters/sovrnXsp/sovrnXsp.go b/adapters/sovrnXsp/sovrnXsp.go index 7dc90adfd7..2a04443233 100644 --- a/adapters/sovrnXsp/sovrnXsp.go +++ b/adapters/sovrnXsp/sovrnXsp.go @@ -5,11 +5,11 @@ import ( "fmt" "net/http" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/sovrnXsp/sovrnXsp_test.go b/adapters/sovrnXsp/sovrnXsp_test.go index 3a82e29a54..6c7e4c546b 100644 --- a/adapters/sovrnXsp/sovrnXsp_test.go +++ b/adapters/sovrnXsp/sovrnXsp_test.go @@ -3,9 +3,9 @@ package sovrnXsp 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) { diff --git a/adapters/sparteo/params_test.go b/adapters/sparteo/params_test.go index 209093d1ef..c7b8d162de 100644 --- a/adapters/sparteo/params_test.go +++ b/adapters/sparteo/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" ) // This file actually intends to test static/bidder-params/sparteo.json diff --git a/adapters/sparteo/sparteo.go b/adapters/sparteo/sparteo.go index 100d5acc71..0653e2c4d7 100644 --- a/adapters/sparteo/sparteo.go +++ b/adapters/sparteo/sparteo.go @@ -5,11 +5,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/sparteo/sparteo_test.go b/adapters/sparteo/sparteo_test.go index 527f98b37e..8e9524dabd 100644 --- a/adapters/sparteo/sparteo_test.go +++ b/adapters/sparteo/sparteo_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/sspBC/sspbc.go b/adapters/sspBC/sspbc.go index 4a12ddaa51..36fce93ffc 100644 --- a/adapters/sspBC/sspbc.go +++ b/adapters/sspBC/sspbc.go @@ -7,12 +7,12 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "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/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/adapters/sspBC/sspbc_test.go b/adapters/sspBC/sspbc_test.go index f2fdc7dae6..a2a61f74c3 100644 --- a/adapters/sspBC/sspbc_test.go +++ b/adapters/sspBC/sspbc_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/startio/startio.go b/adapters/startio/startio.go index b524a66013..6699ab8ee3 100644 --- a/adapters/startio/startio.go +++ b/adapters/startio/startio.go @@ -6,11 +6,11 @@ import ( "slices" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/startio/startio_test.go b/adapters/startio/startio_test.go index 8de9e017ad..5aa321e63f 100644 --- a/adapters/startio/startio_test.go +++ b/adapters/startio/startio_test.go @@ -3,9 +3,9 @@ package startio 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) { diff --git a/adapters/stroeerCore/params_test.go b/adapters/stroeerCore/params_test.go index 4050a21959..6aa2d02d7d 100644 --- a/adapters/stroeerCore/params_test.go +++ b/adapters/stroeerCore/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) { diff --git a/adapters/stroeerCore/stroeercore.go b/adapters/stroeerCore/stroeercore.go index 087a9de7e9..236980fde1 100644 --- a/adapters/stroeerCore/stroeercore.go +++ b/adapters/stroeerCore/stroeercore.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/stroeerCore/stroeercore_test.go b/adapters/stroeerCore/stroeercore_test.go index b0f6204880..4040b34156 100644 --- a/adapters/stroeerCore/stroeercore_test.go +++ b/adapters/stroeerCore/stroeercore_test.go @@ -3,9 +3,9 @@ package stroeerCore 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) { diff --git a/adapters/taboola/params_test.go b/adapters/taboola/params_test.go index 8018c4b9d9..bd1ccddbb0 100644 --- a/adapters/taboola/params_test.go +++ b/adapters/taboola/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) { diff --git a/adapters/taboola/taboola.go b/adapters/taboola/taboola.go index a11fbf6ce7..ec65a4b677 100644 --- a/adapters/taboola/taboola.go +++ b/adapters/taboola/taboola.go @@ -11,12 +11,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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/taboola/taboola_test.go b/adapters/taboola/taboola_test.go index 082e480943..60004ef1ac 100644 --- a/adapters/taboola/taboola_test.go +++ b/adapters/taboola/taboola_test.go @@ -3,9 +3,9 @@ package taboola 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/tappx/params_test.go b/adapters/tappx/params_test.go index 07b56bf80c..2575dffed0 100644 --- a/adapters/tappx/params_test.go +++ b/adapters/tappx/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) { diff --git a/adapters/tappx/tappx.go b/adapters/tappx/tappx.go index 71bad1543b..d0052613e7 100644 --- a/adapters/tappx/tappx.go +++ b/adapters/tappx/tappx.go @@ -11,12 +11,12 @@ import ( "time" "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" ) const TAPPX_BIDDER_VERSION = "1.6" diff --git a/adapters/tappx/tappx_test.go b/adapters/tappx/tappx_test.go index 3643a58cc4..2fc8b61665 100644 --- a/adapters/tappx/tappx_test.go +++ b/adapters/tappx/tappx_test.go @@ -4,9 +4,9 @@ import ( "regexp" "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/adapters/teads/teads.go b/adapters/teads/teads.go index 402392d1cc..81d6eb35ed 100644 --- a/adapters/teads/teads.go +++ b/adapters/teads/teads.go @@ -9,12 +9,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" ) // Builder builds a new instance of the Teads adapter for the given bidder with the given config. diff --git a/adapters/teads/teads_test.go b/adapters/teads/teads_test.go index 8499e6f139..ce61f732c3 100644 --- a/adapters/teads/teads_test.go +++ b/adapters/teads/teads_test.go @@ -3,9 +3,9 @@ package teads 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/telaria/params_test.go b/adapters/telaria/params_test.go index 7b1dfe0854..1ed6d600ed 100644 --- a/adapters/telaria/params_test.go +++ b/adapters/telaria/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) { diff --git a/adapters/telaria/telaria.go b/adapters/telaria/telaria.go index 1805bfaea0..1969ed5a52 100644 --- a/adapters/telaria/telaria.go +++ b/adapters/telaria/telaria.go @@ -7,11 +7,11 @@ import ( "strconv" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const Endpoint = "https://ads.tremorhub.com/ad/rtb/prebid" diff --git a/adapters/telaria/telaria_test.go b/adapters/telaria/telaria_test.go index 8c55e7b900..73fbed3d08 100644 --- a/adapters/telaria/telaria_test.go +++ b/adapters/telaria/telaria_test.go @@ -3,9 +3,9 @@ package telaria 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/teqblaze/params_test.go b/adapters/teqblaze/params_test.go index 2c86ea1485..ac99ad6657 100644 --- a/adapters/teqblaze/params_test.go +++ b/adapters/teqblaze/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) { diff --git a/adapters/teqblaze/teqblaze.go b/adapters/teqblaze/teqblaze.go index b6e391bb85..203ca847c3 100644 --- a/adapters/teqblaze/teqblaze.go +++ b/adapters/teqblaze/teqblaze.go @@ -5,10 +5,10 @@ import ( "net/http" "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/teqblaze/teqblaze_test.go b/adapters/teqblaze/teqblaze_test.go index f4a3cdca92..22537c07e3 100644 --- a/adapters/teqblaze/teqblaze_test.go +++ b/adapters/teqblaze/teqblaze_test.go @@ -3,9 +3,9 @@ package teqblaze 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) { diff --git a/adapters/theadx/params_test.go b/adapters/theadx/params_test.go index 09440b335c..764d5edc32 100644 --- a/adapters/theadx/params_test.go +++ b/adapters/theadx/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" ) // This file actually intends to test static/bidder-params/theadx.json diff --git a/adapters/theadx/theadx.go b/adapters/theadx/theadx.go index 34b1e1a3b4..5460daa83a 100644 --- a/adapters/theadx/theadx.go +++ b/adapters/theadx/theadx.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/theadx/theadx_test.go b/adapters/theadx/theadx_test.go index a945bd15fe..170a3150d1 100644 --- a/adapters/theadx/theadx_test.go +++ b/adapters/theadx/theadx_test.go @@ -3,9 +3,9 @@ package theadx 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) { diff --git a/adapters/thetradedesk/params_test.go b/adapters/thetradedesk/params_test.go index b0829fb290..1cf105857c 100644 --- a/adapters/thetradedesk/params_test.go +++ b/adapters/thetradedesk/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) { diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go index f3d81d2a06..f567b43d9e 100644 --- a/adapters/thetradedesk/thetradedesk.go +++ b/adapters/thetradedesk/thetradedesk.go @@ -10,11 +10,11 @@ import ( "strings" "text/template" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "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/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go index dec4652ce7..050d64498a 100644 --- a/adapters/thetradedesk/thetradedesk_test.go +++ b/adapters/thetradedesk/thetradedesk_test.go @@ -3,15 +3,15 @@ package thetradedesk import ( "encoding/json" "errors" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" "net/http" "testing" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/tpmn/params_test.go b/adapters/tpmn/params_test.go index 674da5fb65..a7159abc4e 100644 --- a/adapters/tpmn/params_test.go +++ b/adapters/tpmn/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" ) var validParams = []string{ diff --git a/adapters/tpmn/tpmn.go b/adapters/tpmn/tpmn.go index 262fc28ac6..95e2d03d35 100644 --- a/adapters/tpmn/tpmn.go +++ b/adapters/tpmn/tpmn.go @@ -7,10 +7,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // TpmnAdapter struct diff --git a/adapters/tpmn/tpmn_test.go b/adapters/tpmn/tpmn_test.go index 865771e89c..f207467fb1 100644 --- a/adapters/tpmn/tpmn_test.go +++ b/adapters/tpmn/tpmn_test.go @@ -3,9 +3,9 @@ package tpmn 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) { diff --git a/adapters/tradplus/params_test.go b/adapters/tradplus/params_test.go index aa92db4a2f..394a8e7b84 100644 --- a/adapters/tradplus/params_test.go +++ b/adapters/tradplus/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) { diff --git a/adapters/tradplus/tradplus.go b/adapters/tradplus/tradplus.go index 4800c73e84..7e7b7a6ecd 100644 --- a/adapters/tradplus/tradplus.go +++ b/adapters/tradplus/tradplus.go @@ -7,12 +7,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/tradplus/tradplus_test.go b/adapters/tradplus/tradplus_test.go index e081607f4e..38dc571e04 100644 --- a/adapters/tradplus/tradplus_test.go +++ b/adapters/tradplus/tradplus_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/trafficgate/params_test.go b/adapters/trafficgate/params_test.go index 0667a8bc5a..a14f887dd9 100644 --- a/adapters/trafficgate/params_test.go +++ b/adapters/trafficgate/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" ) // TestValidParams makes sure that the trafficgate schema accepts all imp.ext fields which we intend to support. diff --git a/adapters/trafficgate/trafficgate.go b/adapters/trafficgate/trafficgate.go index d4d181399d..ce72048ad9 100644 --- a/adapters/trafficgate/trafficgate.go +++ b/adapters/trafficgate/trafficgate.go @@ -7,12 +7,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/trafficgate/trafficgate_test.go b/adapters/trafficgate/trafficgate_test.go index df932538d9..de5c0459cb 100644 --- a/adapters/trafficgate/trafficgate_test.go +++ b/adapters/trafficgate/trafficgate_test.go @@ -3,9 +3,9 @@ package trafficgate 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/triplelift/triplelift.go b/adapters/triplelift/triplelift.go index c5d89cd250..736773075e 100644 --- a/adapters/triplelift/triplelift.go +++ b/adapters/triplelift/triplelift.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type TripleliftAdapter struct { diff --git a/adapters/triplelift/triplelift_test.go b/adapters/triplelift/triplelift_test.go index 1fd5fc8d55..547c8609bb 100644 --- a/adapters/triplelift/triplelift_test.go +++ b/adapters/triplelift/triplelift_test.go @@ -3,9 +3,9 @@ package triplelift 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) { diff --git a/adapters/triplelift_native/params_test.go b/adapters/triplelift_native/params_test.go index 743c3d87ed..1b65fc46fc 100644 --- a/adapters/triplelift_native/params_test.go +++ b/adapters/triplelift_native/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) { diff --git a/adapters/triplelift_native/triplelift_native.go b/adapters/triplelift_native/triplelift_native.go index 1d4c6bf638..987e20d94b 100644 --- a/adapters/triplelift_native/triplelift_native.go +++ b/adapters/triplelift_native/triplelift_native.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type TripleliftNativeAdapter struct { diff --git a/adapters/triplelift_native/triplelift_native_test.go b/adapters/triplelift_native/triplelift_native_test.go index 651890b01e..e3f3b7958c 100644 --- a/adapters/triplelift_native/triplelift_native_test.go +++ b/adapters/triplelift_native/triplelift_native_test.go @@ -3,9 +3,9 @@ package triplelift_native 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/trustedstack/params_test.go b/adapters/trustedstack/params_test.go index a38e0bb722..dee7427456 100644 --- a/adapters/trustedstack/params_test.go +++ b/adapters/trustedstack/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" ) // This file actually intends to test static/bidder-params/trustedstack.json diff --git a/adapters/trustedstack/trustedstack.go b/adapters/trustedstack/trustedstack.go index 7c2fd4df50..0d795620cd 100644 --- a/adapters/trustedstack/trustedstack.go +++ b/adapters/trustedstack/trustedstack.go @@ -7,10 +7,10 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/trustedstack/trustedstack_test.go b/adapters/trustedstack/trustedstack_test.go index d12202802e..223c97b974 100644 --- a/adapters/trustedstack/trustedstack_test.go +++ b/adapters/trustedstack/trustedstack_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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) { diff --git a/adapters/trustx/params_test.go b/adapters/trustx/params_test.go index e0af176ca2..6c785e4174 100644 --- a/adapters/trustx/params_test.go +++ b/adapters/trustx/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" "github.com/stretchr/testify/require" ) diff --git a/adapters/trustx/trustx.go b/adapters/trustx/trustx.go index 3b69f525f4..a36a1985f6 100644 --- a/adapters/trustx/trustx.go +++ b/adapters/trustx/trustx.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type impExt struct { diff --git a/adapters/trustx/trustx_test.go b/adapters/trustx/trustx_test.go index dbfc007826..f3fe9d45e1 100644 --- a/adapters/trustx/trustx_test.go +++ b/adapters/trustx/trustx_test.go @@ -3,9 +3,9 @@ package trustx 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" "github.com/stretchr/testify/require" ) diff --git a/adapters/ucfunnel/params_test.go b/adapters/ucfunnel/params_test.go index 47954e8aad..ca9556ff6b 100644 --- a/adapters/ucfunnel/params_test.go +++ b/adapters/ucfunnel/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" ) // This file actually intends to test static/bidder-params/ucfunnel.json diff --git a/adapters/ucfunnel/ucfunnel.go b/adapters/ucfunnel/ucfunnel.go index efee7736d4..e48c3dd158 100644 --- a/adapters/ucfunnel/ucfunnel.go +++ b/adapters/ucfunnel/ucfunnel.go @@ -7,11 +7,11 @@ import ( "net/url" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type UcfunnelAdapter struct { diff --git a/adapters/ucfunnel/ucfunnel_test.go b/adapters/ucfunnel/ucfunnel_test.go index ec1b777c79..0e0500a0ea 100644 --- a/adapters/ucfunnel/ucfunnel_test.go +++ b/adapters/ucfunnel/ucfunnel_test.go @@ -6,9 +6,9 @@ import ( "testing" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adapters/undertone/params_test.go b/adapters/undertone/params_test.go index dad74a08e8..126a8c4afa 100644 --- a/adapters/undertone/params_test.go +++ b/adapters/undertone/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) { diff --git a/adapters/undertone/undertone.go b/adapters/undertone/undertone.go index 91b2527c6d..522a4a8857 100644 --- a/adapters/undertone/undertone.go +++ b/adapters/undertone/undertone.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const adapterId = 4 diff --git a/adapters/undertone/undertone_test.go b/adapters/undertone/undertone_test.go index 45281a1d15..5c55412184 100644 --- a/adapters/undertone/undertone_test.go +++ b/adapters/undertone/undertone_test.go @@ -3,9 +3,9 @@ package undertone 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) { diff --git a/adapters/unicorn/params_test.go b/adapters/unicorn/params_test.go index 89768ea824..8080688400 100644 --- a/adapters/unicorn/params_test.go +++ b/adapters/unicorn/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) { diff --git a/adapters/unicorn/unicorn.go b/adapters/unicorn/unicorn.go index a957cff9a1..ebaaab17fc 100644 --- a/adapters/unicorn/unicorn.go +++ b/adapters/unicorn/unicorn.go @@ -8,11 +8,11 @@ import ( "github.com/buger/jsonparser" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/unicorn/unicorn_test.go b/adapters/unicorn/unicorn_test.go index a83951277f..646001927f 100644 --- a/adapters/unicorn/unicorn_test.go +++ b/adapters/unicorn/unicorn_test.go @@ -3,9 +3,9 @@ package unicorn 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) { diff --git a/adapters/unruly/params_test.go b/adapters/unruly/params_test.go index 132afee8e1..cbda246310 100644 --- a/adapters/unruly/params_test.go +++ b/adapters/unruly/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) { diff --git a/adapters/unruly/unruly.go b/adapters/unruly/unruly.go index c8e73de99b..4acf708f25 100644 --- a/adapters/unruly/unruly.go +++ b/adapters/unruly/unruly.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/unruly/unruly_test.go b/adapters/unruly/unruly_test.go index e3df3d8881..dc86bb3e68 100644 --- a/adapters/unruly/unruly_test.go +++ b/adapters/unruly/unruly_test.go @@ -3,9 +3,9 @@ package unruly 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) { diff --git a/adapters/vidazoo/params_test.go b/adapters/vidazoo/params_test.go index cfd3e9b5d4..42d77bdd6c 100644 --- a/adapters/vidazoo/params_test.go +++ b/adapters/vidazoo/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) { diff --git a/adapters/vidazoo/vidazoo.go b/adapters/vidazoo/vidazoo.go index be0cf66d9d..0f98d8a2e8 100644 --- a/adapters/vidazoo/vidazoo.go +++ b/adapters/vidazoo/vidazoo.go @@ -8,11 +8,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/vidazoo/vidazoo_test.go b/adapters/vidazoo/vidazoo_test.go index 5d6090de95..49116c425f 100644 --- a/adapters/vidazoo/vidazoo_test.go +++ b/adapters/vidazoo/vidazoo_test.go @@ -3,9 +3,9 @@ package vidazoo 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) { diff --git a/adapters/videobyte/params_test.go b/adapters/videobyte/params_test.go index ffb37f88d9..977409c11c 100644 --- a/adapters/videobyte/params_test.go +++ b/adapters/videobyte/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" ) // This file actually intends to test static/bidder-params/videobyte.json diff --git a/adapters/videobyte/videobyte.go b/adapters/videobyte/videobyte.go index ed79c6525b..5968d9257b 100644 --- a/adapters/videobyte/videobyte.go +++ b/adapters/videobyte/videobyte.go @@ -6,11 +6,11 @@ import ( "net/http" "net/url" - "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" ) diff --git a/adapters/videobyte/videobyte_test.go b/adapters/videobyte/videobyte_test.go index 2d1d2a07fd..cd5cdf5124 100644 --- a/adapters/videobyte/videobyte_test.go +++ b/adapters/videobyte/videobyte_test.go @@ -3,9 +3,9 @@ package videobyte import ( "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" - "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/videoheroes/params_test.go b/adapters/videoheroes/params_test.go index e8af1f1fcf..f927d5724c 100644 --- a/adapters/videoheroes/params_test.go +++ b/adapters/videoheroes/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) { diff --git a/adapters/videoheroes/videoheroes.go b/adapters/videoheroes/videoheroes.go index 8d1d7450cb..80956d56dc 100755 --- a/adapters/videoheroes/videoheroes.go +++ b/adapters/videoheroes/videoheroes.go @@ -7,12 +7,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/videoheroes/videoheroes_test.go b/adapters/videoheroes/videoheroes_test.go index 3545b601dc..c999441007 100644 --- a/adapters/videoheroes/videoheroes_test.go +++ b/adapters/videoheroes/videoheroes_test.go @@ -3,9 +3,9 @@ package videoheroes 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/vidoomy/params_test.go b/adapters/vidoomy/params_test.go index b3801c637c..1052816be5 100644 --- a/adapters/vidoomy/params_test.go +++ b/adapters/vidoomy/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" ) // This file actually intends to test static/bidder-params/vidoomy.json diff --git a/adapters/vidoomy/vidoomy.go b/adapters/vidoomy/vidoomy.go index b39448a414..c7dda9c774 100644 --- a/adapters/vidoomy/vidoomy.go +++ b/adapters/vidoomy/vidoomy.go @@ -7,12 +7,12 @@ import ( "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type adapter struct { diff --git a/adapters/vidoomy/vidoomy_test.go b/adapters/vidoomy/vidoomy_test.go index ef561b596b..c6950cf8b4 100644 --- a/adapters/vidoomy/vidoomy_test.go +++ b/adapters/vidoomy/vidoomy_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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 TestVidoomyBidderEndpointConfig(t *testing.T) { diff --git a/adapters/visiblemeasures/params_test.go b/adapters/visiblemeasures/params_test.go index b4e5bb66c1..e4bbbe2885 100644 --- a/adapters/visiblemeasures/params_test.go +++ b/adapters/visiblemeasures/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) { diff --git a/adapters/visiblemeasures/visiblemeasures.go b/adapters/visiblemeasures/visiblemeasures.go index 100ba03e59..a024c5e3a4 100644 --- a/adapters/visiblemeasures/visiblemeasures.go +++ b/adapters/visiblemeasures/visiblemeasures.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/visiblemeasures/visiblemeasures_test.go b/adapters/visiblemeasures/visiblemeasures_test.go index 8203893835..718c4b2dea 100644 --- a/adapters/visiblemeasures/visiblemeasures_test.go +++ b/adapters/visiblemeasures/visiblemeasures_test.go @@ -3,9 +3,9 @@ package visiblemeasures 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) { diff --git a/adapters/visx/params_test.go b/adapters/visx/params_test.go index 1355d6f8d9..de8925866e 100644 --- a/adapters/visx/params_test.go +++ b/adapters/visx/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) { diff --git a/adapters/visx/visx.go b/adapters/visx/visx.go index 36f62ab298..2014ef3a63 100644 --- a/adapters/visx/visx.go +++ b/adapters/visx/visx.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type VisxAdapter struct { diff --git a/adapters/visx/visx_test.go b/adapters/visx/visx_test.go index d2adffddce..dd1dd999f7 100644 --- a/adapters/visx/visx_test.go +++ b/adapters/visx/visx_test.go @@ -3,9 +3,9 @@ package visx 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) { diff --git a/adapters/vox/params_test.go b/adapters/vox/params_test.go index 536503555e..5438bc9dff 100644 --- a/adapters/vox/params_test.go +++ b/adapters/vox/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) { diff --git a/adapters/vox/vox.go b/adapters/vox/vox.go index 3e5f03aa6e..5918e2dba9 100644 --- a/adapters/vox/vox.go +++ b/adapters/vox/vox.go @@ -5,10 +5,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/vox/vox_test.go b/adapters/vox/vox_test.go index dce89de3af..4e057e2b27 100644 --- a/adapters/vox/vox_test.go +++ b/adapters/vox/vox_test.go @@ -3,9 +3,9 @@ package vox 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) { diff --git a/adapters/vrtcal/params_test.go b/adapters/vrtcal/params_test.go index 8ba180db2b..1e0aa94874 100644 --- a/adapters/vrtcal/params_test.go +++ b/adapters/vrtcal/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" ) //Vrtcal doesn't currently require any custom fields. This file is included for conformity only diff --git a/adapters/vrtcal/vrtcal.go b/adapters/vrtcal/vrtcal.go index e0df0bca95..d342fc44c1 100644 --- a/adapters/vrtcal/vrtcal.go +++ b/adapters/vrtcal/vrtcal.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type VrtcalAdapter struct { diff --git a/adapters/vrtcal/vrtcal_test.go b/adapters/vrtcal/vrtcal_test.go index 59d29aaee3..72efdd5f18 100644 --- a/adapters/vrtcal/vrtcal_test.go +++ b/adapters/vrtcal/vrtcal_test.go @@ -3,9 +3,9 @@ package vrtcal 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) { diff --git a/adapters/vungle/param_test.go b/adapters/vungle/param_test.go index 7053669edf..114637d27d 100644 --- a/adapters/vungle/param_test.go +++ b/adapters/vungle/param_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" ) var validParams = []string{ diff --git a/adapters/vungle/vungle.go b/adapters/vungle/vungle.go index 6e6967fc22..43785b3d98 100644 --- a/adapters/vungle/vungle.go +++ b/adapters/vungle/vungle.go @@ -8,10 +8,10 @@ import ( "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/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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const SupportedCurrency = "USD" diff --git a/adapters/vungle/vungle_test.go b/adapters/vungle/vungle_test.go index 740208dbe0..687edb21bc 100644 --- a/adapters/vungle/vungle_test.go +++ b/adapters/vungle/vungle_test.go @@ -3,9 +3,9 @@ package vungle 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) { diff --git a/adapters/xeworks/params_test.go b/adapters/xeworks/params_test.go index 0ce8d99f48..0581e0570f 100644 --- a/adapters/xeworks/params_test.go +++ b/adapters/xeworks/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" ) var validParams = []string{ diff --git a/adapters/xeworks/xeworks.go b/adapters/xeworks/xeworks.go index bd9d179528..10598b6750 100644 --- a/adapters/xeworks/xeworks.go +++ b/adapters/xeworks/xeworks.go @@ -7,12 +7,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 bidType struct { diff --git a/adapters/xeworks/xeworks_test.go b/adapters/xeworks/xeworks_test.go index 842045af1d..f8c566fe42 100644 --- a/adapters/xeworks/xeworks_test.go +++ b/adapters/xeworks/xeworks_test.go @@ -3,9 +3,9 @@ package xeworks 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/yahooAds/params_test.go b/adapters/yahooAds/params_test.go index 42a5c16ae7..9da14a18b0 100644 --- a/adapters/yahooAds/params_test.go +++ b/adapters/yahooAds/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" ) // This file actually intends to test static/bidder-params/yahooAds.json diff --git a/adapters/yahooAds/yahooAds.go b/adapters/yahooAds/yahooAds.go index 4a03bc3e7f..1be27dc3c5 100644 --- a/adapters/yahooAds/yahooAds.go +++ b/adapters/yahooAds/yahooAds.go @@ -6,12 +6,12 @@ import ( "net/http" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type adapter struct { diff --git a/adapters/yahooAds/yahooAds_test.go b/adapters/yahooAds/yahooAds_test.go index 0eaf711faf..6b07ef32c1 100644 --- a/adapters/yahooAds/yahooAds_test.go +++ b/adapters/yahooAds/yahooAds_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "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 TestYahooAdsBidderEndpointConfig(t *testing.T) { diff --git a/adapters/yandex/params_test.go b/adapters/yandex/params_test.go index 0805be1988..d3b872728c 100644 --- a/adapters/yandex/params_test.go +++ b/adapters/yandex/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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/yandex/yandex.go b/adapters/yandex/yandex.go index c6a99e5a2e..e26aba5e94 100644 --- a/adapters/yandex/yandex.go +++ b/adapters/yandex/yandex.go @@ -11,12 +11,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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" ) const ( diff --git a/adapters/yandex/yandex_test.go b/adapters/yandex/yandex_test.go index 7635b1a1b9..29a7feff16 100644 --- a/adapters/yandex/yandex_test.go +++ b/adapters/yandex/yandex_test.go @@ -3,9 +3,9 @@ package yandex 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/yeahmobi/params_test.go b/adapters/yeahmobi/params_test.go index 2b47316df2..8366c19260 100644 --- a/adapters/yeahmobi/params_test.go +++ b/adapters/yeahmobi/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) { diff --git a/adapters/yeahmobi/yeahmobi.go b/adapters/yeahmobi/yeahmobi.go index 934cee5c27..f3b314ad92 100644 --- a/adapters/yeahmobi/yeahmobi.go +++ b/adapters/yeahmobi/yeahmobi.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/yeahmobi/yeahmobi_test.go b/adapters/yeahmobi/yeahmobi_test.go index d822b32d67..452ec6e781 100644 --- a/adapters/yeahmobi/yeahmobi_test.go +++ b/adapters/yeahmobi/yeahmobi_test.go @@ -3,9 +3,9 @@ package yeahmobi 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/yieldlab/params_test.go b/adapters/yieldlab/params_test.go index ac65adc0fe..6ac8fa727b 100644 --- a/adapters/yieldlab/params_test.go +++ b/adapters/yieldlab/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" ) // This file actually intends to test static/bidder-params/yieldlab.json diff --git a/adapters/yieldlab/types.go b/adapters/yieldlab/types.go index 57ee15c923..4740b042ec 100644 --- a/adapters/yieldlab/types.go +++ b/adapters/yieldlab/types.go @@ -4,7 +4,7 @@ import ( "strconv" "time" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type bidResponse struct { diff --git a/adapters/yieldlab/yieldlab.go b/adapters/yieldlab/yieldlab.go index 4466e548af..4193547117 100644 --- a/adapters/yieldlab/yieldlab.go +++ b/adapters/yieldlab/yieldlab.go @@ -12,12 +12,12 @@ import ( "golang.org/x/text/currency" "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" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) // YieldlabAdapter connects the Yieldlab API to prebid server diff --git a/adapters/yieldlab/yieldlab_test.go b/adapters/yieldlab/yieldlab_test.go index 1bea9b12ea..b9fe8ed8a5 100644 --- a/adapters/yieldlab/yieldlab_test.go +++ b/adapters/yieldlab/yieldlab_test.go @@ -8,9 +8,9 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" - "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" ) const testURL = "https://ad.yieldlab.net/testing/" diff --git a/adapters/yieldmo/params_test.go b/adapters/yieldmo/params_test.go index baa566cf71..7c9224180c 100644 --- a/adapters/yieldmo/params_test.go +++ b/adapters/yieldmo/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" ) // This file actually intends to test static/bidder-params/yieldmo.json diff --git a/adapters/yieldmo/yieldmo.go b/adapters/yieldmo/yieldmo.go index 0725f7920c..c4ea2c66d9 100644 --- a/adapters/yieldmo/yieldmo.go +++ b/adapters/yieldmo/yieldmo.go @@ -7,11 +7,11 @@ import ( "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type YieldmoAdapter struct { diff --git a/adapters/yieldmo/yieldmo_test.go b/adapters/yieldmo/yieldmo_test.go index 668e0a375e..62ec8d5dd8 100644 --- a/adapters/yieldmo/yieldmo_test.go +++ b/adapters/yieldmo/yieldmo_test.go @@ -3,9 +3,9 @@ package yieldmo 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) { diff --git a/adapters/yieldone/params_test.go b/adapters/yieldone/params_test.go index 5632546ac3..9f493a6d18 100644 --- a/adapters/yieldone/params_test.go +++ b/adapters/yieldone/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) { diff --git a/adapters/yieldone/yieldone.go b/adapters/yieldone/yieldone.go index b1aa646538..5227861c4b 100644 --- a/adapters/yieldone/yieldone.go +++ b/adapters/yieldone/yieldone.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type YieldoneAdapter struct { diff --git a/adapters/yieldone/yieldone_test.go b/adapters/yieldone/yieldone_test.go index a9831561d4..c729049201 100644 --- a/adapters/yieldone/yieldone_test.go +++ b/adapters/yieldone/yieldone_test.go @@ -3,9 +3,9 @@ package yieldone 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) { diff --git a/adapters/zentotem/zentotem.go b/adapters/zentotem/zentotem.go index 65c067443e..428cc2c449 100644 --- a/adapters/zentotem/zentotem.go +++ b/adapters/zentotem/zentotem.go @@ -4,9 +4,9 @@ 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/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type adapter struct { diff --git a/adapters/zentotem/zentotem_test.go b/adapters/zentotem/zentotem_test.go index cf608c4a41..2b14a34924 100644 --- a/adapters/zentotem/zentotem_test.go +++ b/adapters/zentotem/zentotem_test.go @@ -2,9 +2,9 @@ package zentotem import ( "github.com/prebid/openrtb/v20/openrtb2" - "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" "github.com/stretchr/testify/assert" "testing" ) diff --git a/adapters/zeroclickfraud/zeroclickfraud.go b/adapters/zeroclickfraud/zeroclickfraud.go index eecd1dd858..08d0040241 100644 --- a/adapters/zeroclickfraud/zeroclickfraud.go +++ b/adapters/zeroclickfraud/zeroclickfraud.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 ZeroClickFraudAdapter struct { diff --git a/adapters/zeroclickfraud/zeroclickfraud_test.go b/adapters/zeroclickfraud/zeroclickfraud_test.go index 363f37c0e1..d10b226bc7 100644 --- a/adapters/zeroclickfraud/zeroclickfraud_test.go +++ b/adapters/zeroclickfraud/zeroclickfraud_test.go @@ -3,9 +3,9 @@ package zeroclickfraud 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/zeta_global_ssp/params_test.go b/adapters/zeta_global_ssp/params_test.go index d665d3da0f..a1c26968b9 100644 --- a/adapters/zeta_global_ssp/params_test.go +++ b/adapters/zeta_global_ssp/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) { diff --git a/adapters/zeta_global_ssp/zeta_global_ssp.go b/adapters/zeta_global_ssp/zeta_global_ssp.go index 59a912c162..9f491ed2b5 100644 --- a/adapters/zeta_global_ssp/zeta_global_ssp.go +++ b/adapters/zeta_global_ssp/zeta_global_ssp.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/zeta_global_ssp/zeta_global_ssp_test.go b/adapters/zeta_global_ssp/zeta_global_ssp_test.go index f7e9b36698..d68b55b85a 100644 --- a/adapters/zeta_global_ssp/zeta_global_ssp_test.go +++ b/adapters/zeta_global_ssp/zeta_global_ssp_test.go @@ -3,9 +3,9 @@ package zeta_global_ssp 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" "github.com/stretchr/testify/assert" ) diff --git a/adapters/zmaticoo/params_test.go b/adapters/zmaticoo/params_test.go index c6c462155a..1360bfbe96 100644 --- a/adapters/zmaticoo/params_test.go +++ b/adapters/zmaticoo/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) { diff --git a/adapters/zmaticoo/zmaticoo.go b/adapters/zmaticoo/zmaticoo.go index 9e0da9e449..93703d5f72 100644 --- a/adapters/zmaticoo/zmaticoo.go +++ b/adapters/zmaticoo/zmaticoo.go @@ -6,11 +6,11 @@ import ( "net/http" "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" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { diff --git a/adapters/zmaticoo/zmaticoo_test.go b/adapters/zmaticoo/zmaticoo_test.go index df12c1e1b6..7bd5c6f674 100644 --- a/adapters/zmaticoo/zmaticoo_test.go +++ b/adapters/zmaticoo/zmaticoo_test.go @@ -3,9 +3,9 @@ package zmaticoo 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) { diff --git a/adservertargeting/adservertargeting.go b/adservertargeting/adservertargeting.go index 3ab7cefe6c..993d6387bd 100644 --- a/adservertargeting/adservertargeting.go +++ b/adservertargeting/adservertargeting.go @@ -7,7 +7,7 @@ import ( "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type DataSource string diff --git a/adservertargeting/adservertargeting_test.go b/adservertargeting/adservertargeting_test.go index 8ba3c256b3..10e3090d29 100644 --- a/adservertargeting/adservertargeting_test.go +++ b/adservertargeting/adservertargeting_test.go @@ -7,8 +7,8 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/adservertargeting/reqcache.go b/adservertargeting/reqcache.go index 03c87f024c..c1b701bdf3 100644 --- a/adservertargeting/reqcache.go +++ b/adservertargeting/reqcache.go @@ -5,7 +5,7 @@ import ( "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type requestCache struct { diff --git a/adservertargeting/requestlookup.go b/adservertargeting/requestlookup.go index 6829971651..99545b8161 100644 --- a/adservertargeting/requestlookup.go +++ b/adservertargeting/requestlookup.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/buger/jsonparser" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func getAdServerTargeting(reqWrapper *openrtb_ext.RequestWrapper) ([]openrtb_ext.AdServerTarget, error) { diff --git a/adservertargeting/requestlookup_test.go b/adservertargeting/requestlookup_test.go index 22f914ac79..c588cdf30d 100644 --- a/adservertargeting/requestlookup_test.go +++ b/adservertargeting/requestlookup_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adservertargeting/respdataprocessor.go b/adservertargeting/respdataprocessor.go index beeaae68de..489e5fc7b6 100644 --- a/adservertargeting/respdataprocessor.go +++ b/adservertargeting/respdataprocessor.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/adservertargeting/respdataprocessor_test.go b/adservertargeting/respdataprocessor_test.go index 973f9b801e..90215a4f1d 100644 --- a/adservertargeting/respdataprocessor_test.go +++ b/adservertargeting/respdataprocessor_test.go @@ -8,7 +8,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/adservertargeting/utils.go b/adservertargeting/utils.go index 7cd4a826b9..9286c896be 100644 --- a/adservertargeting/utils.go +++ b/adservertargeting/utils.go @@ -5,8 +5,8 @@ import ( "strings" "github.com/buger/jsonparser" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func splitAndGet(path string, data []byte, delimiter string) (string, error) { diff --git a/amp/parse.go b/amp/parse.go index 2a86bc7b6b..5437ed3f91 100644 --- a/amp/parse.go +++ b/amp/parse.go @@ -10,10 +10,10 @@ import ( tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - "github.com/prebid/prebid-server/v3/privacy/gdpr" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + "github.com/prebid/prebid-server/v4/privacy/gdpr" ) // Params defines the parameters of an AMP request. diff --git a/amp/parse_test.go b/amp/parse_test.go index 65b69012b4..671d9b0f05 100644 --- a/amp/parse_test.go +++ b/amp/parse_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - "github.com/prebid/prebid-server/v3/privacy/gdpr" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + "github.com/prebid/prebid-server/v4/privacy/gdpr" "github.com/stretchr/testify/assert" ) diff --git a/analytics/agma/agma_module.go b/analytics/agma/agma_module.go index 1e544fe606..518956d58d 100644 --- a/analytics/agma/agma_module.go +++ b/analytics/agma/agma_module.go @@ -13,10 +13,10 @@ import ( "github.com/benbjohnson/clock" "github.com/docker/go-units" "github.com/prebid/go-gdpr/vendorconsent" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type httpSender = func(payload []byte) error diff --git a/analytics/agma/agma_module_test.go b/analytics/agma/agma_module_test.go index 61a6e52755..20325ebb53 100644 --- a/analytics/agma/agma_module_test.go +++ b/analytics/agma/agma_module_test.go @@ -11,9 +11,9 @@ import ( "github.com/benbjohnson/clock" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/analytics/agma/model.go b/analytics/agma/model.go index 112ce961a0..b48d39aebd 100644 --- a/analytics/agma/model.go +++ b/analytics/agma/model.go @@ -5,8 +5,8 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type EventType string diff --git a/analytics/agma/model_test.go b/analytics/agma/model_test.go index 925856b87b..35340bd274 100644 --- a/analytics/agma/model_test.go +++ b/analytics/agma/model_test.go @@ -5,7 +5,7 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/analytics/agma/sender.go b/analytics/agma/sender.go index e3f9c76852..28a0825b07 100644 --- a/analytics/agma/sender.go +++ b/analytics/agma/sender.go @@ -10,9 +10,9 @@ import ( "net/url" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/version" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/version" ) func compressToGZIP(requestBody []byte) ([]byte, error) { diff --git a/analytics/agma/sender_test.go b/analytics/agma/sender_test.go index 1d23e6b6a9..e4a2553c9e 100644 --- a/analytics/agma/sender_test.go +++ b/analytics/agma/sender_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/analytics/build/build.go b/analytics/build/build.go index 3fc3d212e2..3a74826f7b 100644 --- a/analytics/build/build.go +++ b/analytics/build/build.go @@ -4,16 +4,16 @@ import ( "encoding/json" "github.com/benbjohnson/clock" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/analytics/agma" - "github.com/prebid/prebid-server/v3/analytics/clients" - "github.com/prebid/prebid-server/v3/analytics/filesystem" - "github.com/prebid/prebid-server/v3/analytics/pubstack" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/analytics/agma" + "github.com/prebid/prebid-server/v4/analytics/clients" + "github.com/prebid/prebid-server/v4/analytics/filesystem" + "github.com/prebid/prebid-server/v4/analytics/pubstack" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" ) // Modules that need to be logged to need to be initialized here diff --git a/analytics/build/build_test.go b/analytics/build/build_test.go index ae16e0f749..7c6751b722 100644 --- a/analytics/build/build_test.go +++ b/analytics/build/build_test.go @@ -1,18 +1,18 @@ package build import ( - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iputil" "net/http" "os" "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/analytics/core.go b/analytics/core.go index 7f700774fd..a2b8162c0c 100644 --- a/analytics/core.go +++ b/analytics/core.go @@ -4,9 +4,9 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Module must be implemented by analytics modules to extract the required information and logging diff --git a/analytics/filesystem/file_module.go b/analytics/filesystem/file_module.go index f2ab3c63d9..0342ee9f33 100644 --- a/analytics/filesystem/file_module.go +++ b/analytics/filesystem/file_module.go @@ -6,9 +6,9 @@ import ( cglog "github.com/chasex/glog" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type RequestType string diff --git a/analytics/filesystem/file_module_test.go b/analytics/filesystem/file_module_test.go index 0e502cfb9e..ff5a139ddd 100644 --- a/analytics/filesystem/file_module_test.go +++ b/analytics/filesystem/file_module_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/mock" "github.com/prebid/openrtb/v20/openrtb2" diff --git a/analytics/filesystem/model.go b/analytics/filesystem/model.go index aed111dd10..eec6fd7645 100644 --- a/analytics/filesystem/model.go +++ b/analytics/filesystem/model.go @@ -4,10 +4,10 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type logAuction struct { diff --git a/analytics/pubstack/config.go b/analytics/pubstack/config.go index 38ca4cb139..6548cbc0f5 100644 --- a/analytics/pubstack/config.go +++ b/analytics/pubstack/config.go @@ -9,7 +9,7 @@ import ( "time" "github.com/docker/go-units" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) func fetchConfig(client *http.Client, endpoint *url.URL) (*Configuration, error) { diff --git a/analytics/pubstack/configupdate.go b/analytics/pubstack/configupdate.go index 166e69554d..d570d28da1 100644 --- a/analytics/pubstack/configupdate.go +++ b/analytics/pubstack/configupdate.go @@ -6,7 +6,7 @@ import ( "net/url" "time" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/util/task" ) // ConfigUpdateTask publishes configurations until the stop channel is signaled. diff --git a/analytics/pubstack/eventchannel/eventchannel.go b/analytics/pubstack/eventchannel/eventchannel.go index bde37ee546..7879a6d9d4 100644 --- a/analytics/pubstack/eventchannel/eventchannel.go +++ b/analytics/pubstack/eventchannel/eventchannel.go @@ -7,7 +7,7 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) type Metrics struct { diff --git a/analytics/pubstack/eventchannel/sender.go b/analytics/pubstack/eventchannel/sender.go index 61587ea941..3ea79e2109 100644 --- a/analytics/pubstack/eventchannel/sender.go +++ b/analytics/pubstack/eventchannel/sender.go @@ -8,7 +8,7 @@ import ( "net/url" "path" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) type Sender = func(payload []byte) error diff --git a/analytics/pubstack/helpers/json.go b/analytics/pubstack/helpers/json.go index fbdc173219..ba02a34a26 100644 --- a/analytics/pubstack/helpers/json.go +++ b/analytics/pubstack/helpers/json.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func JsonifyAuctionObject(ao *analytics.AuctionObject, scope string) ([]byte, error) { diff --git a/analytics/pubstack/helpers/json_test.go b/analytics/pubstack/helpers/json_test.go index 1e6282078c..82f56e1bc3 100644 --- a/analytics/pubstack/helpers/json_test.go +++ b/analytics/pubstack/helpers/json_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" + "github.com/prebid/prebid-server/v4/analytics" "github.com/stretchr/testify/assert" ) diff --git a/analytics/pubstack/helpers/model.go b/analytics/pubstack/helpers/model.go index 7dad2f7dad..cdba835e43 100644 --- a/analytics/pubstack/helpers/model.go +++ b/analytics/pubstack/helpers/model.go @@ -4,10 +4,10 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type logAuction struct { diff --git a/analytics/pubstack/pubstack_module.go b/analytics/pubstack/pubstack_module.go index 9a8116951d..965774043a 100644 --- a/analytics/pubstack/pubstack_module.go +++ b/analytics/pubstack/pubstack_module.go @@ -10,10 +10,10 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/analytics/pubstack/eventchannel" - "github.com/prebid/prebid-server/v3/analytics/pubstack/helpers" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/analytics/pubstack/eventchannel" + "github.com/prebid/prebid-server/v4/analytics/pubstack/helpers" + "github.com/prebid/prebid-server/v4/logger" ) type Configuration struct { diff --git a/analytics/pubstack/pubstack_module_test.go b/analytics/pubstack/pubstack_module_test.go index e2b4e118c6..ff590010f6 100644 --- a/analytics/pubstack/pubstack_module_test.go +++ b/analytics/pubstack/pubstack_module_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/analytics/runner.go b/analytics/runner.go index d10370e485..42b422d55e 100644 --- a/analytics/runner.go +++ b/analytics/runner.go @@ -1,7 +1,7 @@ package analytics import ( - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/privacy" ) type Runner interface { diff --git a/bidadjustment/apply.go b/bidadjustment/apply.go index 864d6bf6fb..d3063709ee 100644 --- a/bidadjustment/apply.go +++ b/bidadjustment/apply.go @@ -3,8 +3,8 @@ package bidadjustment import ( "math" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const ( diff --git a/bidadjustment/apply_test.go b/bidadjustment/apply_test.go index 1a9bf75a20..529a5ab527 100644 --- a/bidadjustment/apply_test.go +++ b/bidadjustment/apply_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/bidadjustment/build_rules.go b/bidadjustment/build_rules.go index 2d0ac7c4cd..fbde258440 100644 --- a/bidadjustment/build_rules.go +++ b/bidadjustment/build_rules.go @@ -1,8 +1,8 @@ package bidadjustment import ( - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const ( diff --git a/bidadjustment/build_rules_test.go b/bidadjustment/build_rules_test.go index 29864bcdbc..fd7346c2ac 100644 --- a/bidadjustment/build_rules_test.go +++ b/bidadjustment/build_rules_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/bidadjustment/validate.go b/bidadjustment/validate.go index b5383b4d1b..dd59f12af0 100644 --- a/bidadjustment/validate.go +++ b/bidadjustment/validate.go @@ -3,7 +3,7 @@ package bidadjustment import ( "math" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Validate checks whether all provided bid adjustments are valid or not against the requirements defined in the issue diff --git a/bidadjustment/validate_test.go b/bidadjustment/validate_test.go index dedcddc9af..2ac39bddd7 100644 --- a/bidadjustment/validate_test.go +++ b/bidadjustment/validate_test.go @@ -3,7 +3,7 @@ package bidadjustment import ( "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/config/account.go b/config/account.go index 2d2bfb5cd8..a773e6fbbd 100644 --- a/config/account.go +++ b/config/account.go @@ -7,8 +7,8 @@ import ( "strings" "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iputil" ) // ChannelType enumerates the values of integrations Prebid Server can configure for an account diff --git a/config/account_module_decoder.go b/config/account_module_decoder.go index 950460cc50..20d62e6de4 100644 --- a/config/account_module_decoder.go +++ b/config/account_module_decoder.go @@ -6,7 +6,7 @@ import ( "reflect" "github.com/mitchellh/mapstructure" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // AccountModulesHookFunc returns a mapstructure.DecodeHookFuncType that converts diff --git a/config/account_test.go b/config/account_test.go index 0e1d366caf..8e6d484724 100644 --- a/config/account_test.go +++ b/config/account_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/config/bidderinfo.go b/config/bidderinfo.go index a9add8d93a..20a5512828 100644 --- a/config/bidderinfo.go +++ b/config/bidderinfo.go @@ -8,11 +8,11 @@ import ( "strings" "text/template" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/sliceutil" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/sliceutil" validator "github.com/asaskevich/govalidator" "gopkg.in/yaml.v3" diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go index 1263f273be..ac90a2de84 100644 --- a/config/bidderinfo_test.go +++ b/config/bidderinfo_test.go @@ -7,8 +7,8 @@ import ( "gopkg.in/yaml.v3" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/config/compression.go b/config/compression.go index c838e3390a..c99a893ca9 100644 --- a/config/compression.go +++ b/config/compression.go @@ -1,6 +1,6 @@ package config -import "github.com/prebid/prebid-server/v3/util/httputil" +import "github.com/prebid/prebid-server/v4/util/httputil" type Compression struct { Request CompressionInfo `mapstructure:"request"` diff --git a/config/compression_test.go b/config/compression_test.go index 78e7b6468e..23f4bb5fa4 100644 --- a/config/compression_test.go +++ b/config/compression_test.go @@ -3,7 +3,7 @@ package config import ( "testing" - "github.com/prebid/prebid-server/v3/util/httputil" + "github.com/prebid/prebid-server/v4/util/httputil" "github.com/stretchr/testify/assert" ) diff --git a/config/config.go b/config/config.go index 30475b2241..ad635c199c 100644 --- a/config/config.go +++ b/config/config.go @@ -11,10 +11,10 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/spf13/viper" ) diff --git a/config/config_test.go b/config/config_test.go index 7c5391cecc..5f9cb0996f 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -10,8 +10,8 @@ import ( "time" "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) diff --git a/config/stored_requests.go b/config/stored_requests.go index 73acc1bf06..92eab4ea8e 100644 --- a/config/stored_requests.go +++ b/config/stored_requests.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) // DataType constants diff --git a/config/structlog.go b/config/structlog.go index 4b088f2315..d89af631e5 100644 --- a/config/structlog.go +++ b/config/structlog.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - logInternal "github.com/prebid/prebid-server/v3/logger" + logInternal "github.com/prebid/prebid-server/v4/logger" ) type logMsg func(string, ...interface{}) diff --git a/currency/currency.go b/currency/currency.go index b4d886274e..236c2235db 100644 --- a/currency/currency.go +++ b/currency/currency.go @@ -1,7 +1,7 @@ package currency import ( - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func GetAuctionCurrencyRates(currencyConverter *RateConverter, requestRates *openrtb_ext.ExtRequestCurrency) Conversions { diff --git a/currency/currency_test.go b/currency/currency_test.go index c29c8d18e7..f8ceb3ac27 100644 --- a/currency/currency_test.go +++ b/currency/currency_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/currency/rate_converter.go b/currency/rate_converter.go index c791c9b665..ba7639df9b 100644 --- a/currency/rate_converter.go +++ b/currency/rate_converter.go @@ -8,10 +8,10 @@ import ( "sync/atomic" "time" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) // RateConverter holds the currencies conversion rates dictionary diff --git a/currency/rate_converter_test.go b/currency/rate_converter_test.go index 0698a7ba27..c218128dda 100644 --- a/currency/rate_converter_test.go +++ b/currency/rate_converter_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/util/task" "github.com/stretchr/testify/assert" ) diff --git a/currency/rates_test.go b/currency/rates_test.go index 555d299d21..f922fa62a9 100644 --- a/currency/rates_test.go +++ b/currency/rates_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "golang.org/x/text/currency" ) diff --git a/currency/validation.go b/currency/validation.go index 5e23362e5b..45b2522a59 100644 --- a/currency/validation.go +++ b/currency/validation.go @@ -5,8 +5,8 @@ import ( "golang.org/x/text/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // ValidateCustomRates throws a bad input error if any of the 3-digit currency codes found in diff --git a/currency/validation_test.go b/currency/validation_test.go index 0edd5c89a3..fd22c2efd2 100644 --- a/currency/validation_test.go +++ b/currency/validation_test.go @@ -3,8 +3,8 @@ package currency import ( "testing" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/dsa/validate.go b/dsa/validate.go index 3dce2fba1c..09f97456f4 100644 --- a/dsa/validate.go +++ b/dsa/validate.go @@ -3,9 +3,9 @@ package dsa import ( "errors" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // Required values representing whether a DSA object is required diff --git a/dsa/validate_test.go b/dsa/validate_test.go index e0af9bc80a..104ef1154c 100644 --- a/dsa/validate_test.go +++ b/dsa/validate_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/dsa/writer.go b/dsa/writer.go index 33d0bda6d3..9e5d164e76 100644 --- a/dsa/writer.go +++ b/dsa/writer.go @@ -1,8 +1,8 @@ package dsa import ( - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Writer is used to write the default DSA to the request (req.regs.ext.dsa) diff --git a/dsa/writer_test.go b/dsa/writer_test.go index bbe82e0b69..04826c408a 100644 --- a/dsa/writer_test.go +++ b/dsa/writer_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index 6c71072e7c..0c1c1fb274 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -15,23 +15,23 @@ import ( "github.com/julienschmidt/httprouter" gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - gppPrivacy "github.com/prebid/prebid-server/v3/privacy/gpp" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/jsonutil" - stringutil "github.com/prebid/prebid-server/v3/util/stringutil" - "github.com/prebid/prebid-server/v3/util/timeutil" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + gppPrivacy "github.com/prebid/prebid-server/v4/privacy/gpp" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/jsonutil" + stringutil "github.com/prebid/prebid-server/v4/util/stringutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) const receiveCookieDeprecation = "receive-cookie-deprecation" diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index 208627ab8f..3da85fb71a 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -15,17 +15,17 @@ import ( "testing/iotest" "time" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/endpoints/currency_rates.go b/endpoints/currency_rates.go index f7d20cd79b..c6cacc6738 100644 --- a/endpoints/currency_rates.go +++ b/endpoints/currency_rates.go @@ -4,9 +4,9 @@ import ( "net/http" "time" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // currencyRatesInfo holds currency rates information. diff --git a/endpoints/currency_rates_test.go b/endpoints/currency_rates_test.go index 00da093a2d..21d314a9f9 100644 --- a/endpoints/currency_rates_test.go +++ b/endpoints/currency_rates_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/currency" + "github.com/prebid/prebid-server/v4/currency" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/events/account_test.go b/endpoints/events/account_test.go index b379621b06..cbd0a5c818 100644 --- a/endpoints/events/account_test.go +++ b/endpoints/events/account_test.go @@ -9,10 +9,10 @@ import ( "testing" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/endpoints/events/event.go b/endpoints/events/event.go index fa2fca2f96..c1a253b3d3 100644 --- a/endpoints/events/event.go +++ b/endpoints/events/event.go @@ -10,17 +10,17 @@ import ( "time" "unicode" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/julienschmidt/httprouter" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/httputil" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/httputil" ) const ( diff --git a/endpoints/events/event_test.go b/endpoints/events/event_test.go index eb52d8c128..8a32da7b25 100644 --- a/endpoints/events/event_test.go +++ b/endpoints/events/event_test.go @@ -12,12 +12,12 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/events/vtrack.go b/endpoints/events/vtrack.go index ff846f694f..9a2e6ce5f3 100644 --- a/endpoints/events/vtrack.go +++ b/endpoints/events/vtrack.go @@ -10,16 +10,16 @@ import ( "time" "github.com/julienschmidt/httprouter" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/jsonutil" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/endpoints/events/vtrack_test.go b/endpoints/events/vtrack_test.go index 1345d563db..0648bdbbb4 100644 --- a/endpoints/events/vtrack_test.go +++ b/endpoints/events/vtrack_test.go @@ -12,11 +12,11 @@ import ( "strings" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/getuids.go b/endpoints/getuids.go index dac114da22..ecc176b07a 100644 --- a/endpoints/getuids.go +++ b/endpoints/getuids.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/usersync" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/usersync" "encoding/json" ) diff --git a/endpoints/getuids_test.go b/endpoints/getuids_test.go index 1092c51f79..6b0ff5a7cc 100644 --- a/endpoints/getuids_test.go +++ b/endpoints/getuids_test.go @@ -5,7 +5,7 @@ import ( "net/http/httptest" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/info/bidders.go b/endpoints/info/bidders.go index d5f6ea330f..67b9887314 100644 --- a/endpoints/info/bidders.go +++ b/endpoints/info/bidders.go @@ -6,9 +6,9 @@ import ( "strings" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) var invalidEnabledOnlyMsg = []byte(`Invalid value for 'enabledonly' query param, must be of boolean type`) diff --git a/endpoints/info/bidders_detail.go b/endpoints/info/bidders_detail.go index 1a0936a07b..5bf97f3cea 100644 --- a/endpoints/info/bidders_detail.go +++ b/endpoints/info/bidders_detail.go @@ -7,10 +7,10 @@ import ( "strings" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/endpoints/info/bidders_detail_test.go b/endpoints/info/bidders_detail_test.go index d98e9ec094..2ee6df0f56 100644 --- a/endpoints/info/bidders_detail_test.go +++ b/endpoints/info/bidders_detail_test.go @@ -9,9 +9,9 @@ import ( "testing" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/info/bidders_test.go b/endpoints/info/bidders_test.go index 20b5ea0401..9a30c28756 100644 --- a/endpoints/info/bidders_test.go +++ b/endpoints/info/bidders_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 48a80d9cab..cb494d2876 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -15,29 +15,29 @@ import ( "github.com/julienschmidt/httprouter" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/util/uuidutil" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/util/uuidutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/amp" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/version" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/amp" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) const defaultAmpRequestTimeoutMillis = 900 diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go index 126d86802b..44aeb23da6 100644 --- a/endpoints/openrtb2/amp_auction_test.go +++ b/endpoints/openrtb2/amp_auction_test.go @@ -19,23 +19,23 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/amp" - "github.com/prebid/prebid-server/v3/analytics" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/amp" + "github.com/prebid/prebid-server/v4/analytics" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // TestGoodRequests makes sure that the auction runs properly-formatted stored bids correctly. diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 0eaf0e302e..bebaab091b 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -21,38 +21,38 @@ import ( "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "github.com/prebid/prebid-server/v3/bidadjustment" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacysandbox" - "github.com/prebid/prebid-server/v3/schain" + "github.com/prebid/prebid-server/v4/bidadjustment" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacysandbox" + "github.com/prebid/prebid-server/v4/schain" "golang.org/x/net/publicsuffix" jsonpatch "gopkg.in/evanphx/json-patch.v5" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - "github.com/prebid/prebid-server/v3/privacy/lmt" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/httputil" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/uuidutil" - "github.com/prebid/prebid-server/v3/version" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + "github.com/prebid/prebid-server/v4/privacy/lmt" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/httputil" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/uuidutil" + "github.com/prebid/prebid-server/v4/version" ) const ampChannel = "amp" diff --git a/endpoints/openrtb2/auction_benchmark_test.go b/endpoints/openrtb2/auction_benchmark_test.go index ab8cb4863a..7d963393b8 100644 --- a/endpoints/openrtb2/auction_benchmark_test.go +++ b/endpoints/openrtb2/auction_benchmark_test.go @@ -10,18 +10,18 @@ import ( "testing" "time" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/macros" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/usersync" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/macros" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/usersync" ) // benchmarkTestServer returns the header bidding test ad. This response was scraped from a real appnexus server response. diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index 65e520a219..947b6442a8 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -23,25 +23,25 @@ import ( "github.com/julienschmidt/httprouter" gpplib "github.com/prebid/go-gpp" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/analytics" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/analytics" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/openrtb2/interstitial.go b/endpoints/openrtb2/interstitial.go index 4cb9482c0d..7f39af0013 100644 --- a/endpoints/openrtb2/interstitial.go +++ b/endpoints/openrtb2/interstitial.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "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/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func processInterstitials(req *openrtb_ext.RequestWrapper) error { diff --git a/endpoints/openrtb2/interstitial_test.go b/endpoints/openrtb2/interstitial_test.go index d5276d18db..5f4e4e154f 100644 --- a/endpoints/openrtb2/interstitial_test.go +++ b/endpoints/openrtb2/interstitial_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go index e320a940e6..d0316db77c 100644 --- a/endpoints/openrtb2/test_utils.go +++ b/endpoints/openrtb2/test_utils.go @@ -18,29 +18,29 @@ import ( "github.com/julienschmidt/httprouter" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/openrtb/v20/openrtb3" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/analytics" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - pbc "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/uuidutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/analytics" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + pbc "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/uuidutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index 9b7a9a3bea..04dffb1dda 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -16,29 +16,29 @@ import ( "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" jsonpatch "gopkg.in/evanphx/json-patch.v5" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/iputil" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/uuidutil" - "github.com/prebid/prebid-server/v3/version" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/iputil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/uuidutil" + "github.com/prebid/prebid-server/v4/version" ) var defaultRequestTimeout int64 = 5000 diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go index 2ba5cea684..1a4d4f9934 100644 --- a/endpoints/openrtb2/video_auction_test.go +++ b/endpoints/openrtb2/video_auction_test.go @@ -11,21 +11,21 @@ import ( "strings" "testing" - "github.com/prebid/prebid-server/v3/analytics" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/analytics" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" diff --git a/endpoints/setuid.go b/endpoints/setuid.go index 8358761003..dcefe4f645 100644 --- a/endpoints/setuid.go +++ b/endpoints/setuid.go @@ -12,19 +12,19 @@ import ( "github.com/julienschmidt/httprouter" gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" - accountService "github.com/prebid/prebid-server/v3/account" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - gppPrivacy "github.com/prebid/prebid-server/v3/privacy/gpp" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/httputil" - stringutil "github.com/prebid/prebid-server/v3/util/stringutil" + accountService "github.com/prebid/prebid-server/v4/account" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + gppPrivacy "github.com/prebid/prebid-server/v4/privacy/gpp" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/httputil" + stringutil "github.com/prebid/prebid-server/v4/util/stringutil" ) const ( diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go index 78944da7c4..015566e5c0 100644 --- a/endpoints/setuid_test.go +++ b/endpoints/setuid_test.go @@ -12,18 +12,18 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/analytics" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/usersync" + "github.com/prebid/prebid-server/v4/analytics" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/usersync" "github.com/stretchr/testify/assert" - metricsConf "github.com/prebid/prebid-server/v3/metrics/config" + metricsConf "github.com/prebid/prebid-server/v4/metrics/config" ) func TestSetUIDEndpoint(t *testing.T) { diff --git a/endpoints/version.go b/endpoints/version.go index b947c771fb..8a1f15599f 100644 --- a/endpoints/version.go +++ b/endpoints/version.go @@ -4,8 +4,8 @@ import ( "encoding/json" "net/http" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const versionEndpointValueNotSet = "not-set" diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index b6ca31eb1c..630fbe348b 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -1,267 +1,267 @@ package exchange import ( - "github.com/prebid/prebid-server/v3/adapters" - ttx "github.com/prebid/prebid-server/v3/adapters/33across" - "github.com/prebid/prebid-server/v3/adapters/aax" - "github.com/prebid/prebid-server/v3/adapters/aceex" - "github.com/prebid/prebid-server/v3/adapters/acuityads" - "github.com/prebid/prebid-server/v3/adapters/adagio" - "github.com/prebid/prebid-server/v3/adapters/adelement" - "github.com/prebid/prebid-server/v3/adapters/adf" - "github.com/prebid/prebid-server/v3/adapters/adgeneration" - "github.com/prebid/prebid-server/v3/adapters/adhese" - "github.com/prebid/prebid-server/v3/adapters/adkernel" - "github.com/prebid/prebid-server/v3/adapters/adkernelAdn" - "github.com/prebid/prebid-server/v3/adapters/adman" - "github.com/prebid/prebid-server/v3/adapters/admatic" - "github.com/prebid/prebid-server/v3/adapters/admixer" - "github.com/prebid/prebid-server/v3/adapters/adnuntius" - "github.com/prebid/prebid-server/v3/adapters/adot" - "github.com/prebid/prebid-server/v3/adapters/adpone" - "github.com/prebid/prebid-server/v3/adapters/adprime" - "github.com/prebid/prebid-server/v3/adapters/adquery" - "github.com/prebid/prebid-server/v3/adapters/adrino" - "github.com/prebid/prebid-server/v3/adapters/adtarget" - "github.com/prebid/prebid-server/v3/adapters/adtelligent" - "github.com/prebid/prebid-server/v3/adapters/adtonos" - "github.com/prebid/prebid-server/v3/adapters/adtrgtme" - "github.com/prebid/prebid-server/v3/adapters/aduptech" - "github.com/prebid/prebid-server/v3/adapters/advangelists" - "github.com/prebid/prebid-server/v3/adapters/adverxo" - "github.com/prebid/prebid-server/v3/adapters/adview" - "github.com/prebid/prebid-server/v3/adapters/adxcg" - "github.com/prebid/prebid-server/v3/adapters/adyoulike" - "github.com/prebid/prebid-server/v3/adapters/afront" - "github.com/prebid/prebid-server/v3/adapters/aidem" - "github.com/prebid/prebid-server/v3/adapters/aja" - "github.com/prebid/prebid-server/v3/adapters/akcelo" - "github.com/prebid/prebid-server/v3/adapters/algorix" - "github.com/prebid/prebid-server/v3/adapters/alkimi" - alliance_gravity "github.com/prebid/prebid-server/v3/adapters/alliance_gravity" - "github.com/prebid/prebid-server/v3/adapters/amx" - "github.com/prebid/prebid-server/v3/adapters/apacdex" - "github.com/prebid/prebid-server/v3/adapters/appnexus" - "github.com/prebid/prebid-server/v3/adapters/appush" - "github.com/prebid/prebid-server/v3/adapters/aso" - "github.com/prebid/prebid-server/v3/adapters/audienceNetwork" - "github.com/prebid/prebid-server/v3/adapters/automatad" - "github.com/prebid/prebid-server/v3/adapters/avocet" - "github.com/prebid/prebid-server/v3/adapters/axis" - "github.com/prebid/prebid-server/v3/adapters/axonix" - "github.com/prebid/prebid-server/v3/adapters/beachfront" - "github.com/prebid/prebid-server/v3/adapters/beintoo" - "github.com/prebid/prebid-server/v3/adapters/bematterfull" - "github.com/prebid/prebid-server/v3/adapters/beop" - "github.com/prebid/prebid-server/v3/adapters/between" - "github.com/prebid/prebid-server/v3/adapters/beyondmedia" - "github.com/prebid/prebid-server/v3/adapters/bidmachine" - "github.com/prebid/prebid-server/v3/adapters/bidmatic" - "github.com/prebid/prebid-server/v3/adapters/bidmyadz" - "github.com/prebid/prebid-server/v3/adapters/bidscube" - "github.com/prebid/prebid-server/v3/adapters/bidstack" - "github.com/prebid/prebid-server/v3/adapters/bidtheatre" - "github.com/prebid/prebid-server/v3/adapters/bigoad" - "github.com/prebid/prebid-server/v3/adapters/blasto" - "github.com/prebid/prebid-server/v3/adapters/bliink" - "github.com/prebid/prebid-server/v3/adapters/blis" - "github.com/prebid/prebid-server/v3/adapters/blue" - "github.com/prebid/prebid-server/v3/adapters/bluesea" - "github.com/prebid/prebid-server/v3/adapters/bmtm" - "github.com/prebid/prebid-server/v3/adapters/boldwin" - "github.com/prebid/prebid-server/v3/adapters/boldwin_rapid" - "github.com/prebid/prebid-server/v3/adapters/brave" - "github.com/prebid/prebid-server/v3/adapters/bwx" - cadentaperturemx "github.com/prebid/prebid-server/v3/adapters/cadent_aperture_mx" - "github.com/prebid/prebid-server/v3/adapters/ccx" - "github.com/prebid/prebid-server/v3/adapters/clydo" - "github.com/prebid/prebid-server/v3/adapters/cointraffic" - "github.com/prebid/prebid-server/v3/adapters/coinzilla" - "github.com/prebid/prebid-server/v3/adapters/colossus" - "github.com/prebid/prebid-server/v3/adapters/compass" - "github.com/prebid/prebid-server/v3/adapters/concert" - "github.com/prebid/prebid-server/v3/adapters/connatix" - "github.com/prebid/prebid-server/v3/adapters/connectad" - "github.com/prebid/prebid-server/v3/adapters/consumable" - "github.com/prebid/prebid-server/v3/adapters/contxtful" - "github.com/prebid/prebid-server/v3/adapters/conversant" - "github.com/prebid/prebid-server/v3/adapters/copper6ssp" - "github.com/prebid/prebid-server/v3/adapters/cpmstar" - "github.com/prebid/prebid-server/v3/adapters/criteo" - "github.com/prebid/prebid-server/v3/adapters/cwire" - "github.com/prebid/prebid-server/v3/adapters/datablocks" - "github.com/prebid/prebid-server/v3/adapters/decenterads" - "github.com/prebid/prebid-server/v3/adapters/deepintent" - "github.com/prebid/prebid-server/v3/adapters/definemedia" - "github.com/prebid/prebid-server/v3/adapters/dianomi" - "github.com/prebid/prebid-server/v3/adapters/displayio" - "github.com/prebid/prebid-server/v3/adapters/dmx" - "github.com/prebid/prebid-server/v3/adapters/driftpixel" - evolution "github.com/prebid/prebid-server/v3/adapters/e_volution" - "github.com/prebid/prebid-server/v3/adapters/edge226" - "github.com/prebid/prebid-server/v3/adapters/elementaltv" - "github.com/prebid/prebid-server/v3/adapters/emtv" - "github.com/prebid/prebid-server/v3/adapters/eplanning" - "github.com/prebid/prebid-server/v3/adapters/epom" - "github.com/prebid/prebid-server/v3/adapters/escalax" - "github.com/prebid/prebid-server/v3/adapters/exco" - "github.com/prebid/prebid-server/v3/adapters/feedad" - "github.com/prebid/prebid-server/v3/adapters/flatads" - "github.com/prebid/prebid-server/v3/adapters/flipp" - "github.com/prebid/prebid-server/v3/adapters/freewheelssp" - "github.com/prebid/prebid-server/v3/adapters/frvradn" - "github.com/prebid/prebid-server/v3/adapters/fwssp" - "github.com/prebid/prebid-server/v3/adapters/gamma" - "github.com/prebid/prebid-server/v3/adapters/gamoshi" - "github.com/prebid/prebid-server/v3/adapters/globalsun" - "github.com/prebid/prebid-server/v3/adapters/goldbach" - "github.com/prebid/prebid-server/v3/adapters/grid" - "github.com/prebid/prebid-server/v3/adapters/gumgum" - "github.com/prebid/prebid-server/v3/adapters/huaweiads" - "github.com/prebid/prebid-server/v3/adapters/imds" - "github.com/prebid/prebid-server/v3/adapters/impactify" - "github.com/prebid/prebid-server/v3/adapters/improvedigital" - "github.com/prebid/prebid-server/v3/adapters/infytv" - "github.com/prebid/prebid-server/v3/adapters/inmobi" - "github.com/prebid/prebid-server/v3/adapters/insticator" - "github.com/prebid/prebid-server/v3/adapters/intenze" - "github.com/prebid/prebid-server/v3/adapters/interactiveoffers" - "github.com/prebid/prebid-server/v3/adapters/invibes" - "github.com/prebid/prebid-server/v3/adapters/iqx" - "github.com/prebid/prebid-server/v3/adapters/iqzone" - "github.com/prebid/prebid-server/v3/adapters/ix" - "github.com/prebid/prebid-server/v3/adapters/jixie" - "github.com/prebid/prebid-server/v3/adapters/kargo" - "github.com/prebid/prebid-server/v3/adapters/kayzen" - "github.com/prebid/prebid-server/v3/adapters/kidoz" - "github.com/prebid/prebid-server/v3/adapters/kiviads" - "github.com/prebid/prebid-server/v3/adapters/kobler" - "github.com/prebid/prebid-server/v3/adapters/krushmedia" - "github.com/prebid/prebid-server/v3/adapters/kueezrtb" - "github.com/prebid/prebid-server/v3/adapters/lemmadigital" - "github.com/prebid/prebid-server/v3/adapters/limelightDigital" - lmkiviads "github.com/prebid/prebid-server/v3/adapters/lm_kiviads" - "github.com/prebid/prebid-server/v3/adapters/lockerdome" - "github.com/prebid/prebid-server/v3/adapters/logan" - "github.com/prebid/prebid-server/v3/adapters/logicad" - "github.com/prebid/prebid-server/v3/adapters/loopme" - "github.com/prebid/prebid-server/v3/adapters/loyal" - "github.com/prebid/prebid-server/v3/adapters/lunamedia" - "github.com/prebid/prebid-server/v3/adapters/mabidder" - "github.com/prebid/prebid-server/v3/adapters/madsense" - "github.com/prebid/prebid-server/v3/adapters/madvertise" - "github.com/prebid/prebid-server/v3/adapters/marsmedia" - "github.com/prebid/prebid-server/v3/adapters/mediago" - "github.com/prebid/prebid-server/v3/adapters/medianet" - "github.com/prebid/prebid-server/v3/adapters/mediasquare" - "github.com/prebid/prebid-server/v3/adapters/melozen" - "github.com/prebid/prebid-server/v3/adapters/metax" - "github.com/prebid/prebid-server/v3/adapters/mgid" - "github.com/prebid/prebid-server/v3/adapters/mgidX" - "github.com/prebid/prebid-server/v3/adapters/minutemedia" - "github.com/prebid/prebid-server/v3/adapters/missena" - "github.com/prebid/prebid-server/v3/adapters/mobfoxpb" - "github.com/prebid/prebid-server/v3/adapters/mobilefuse" - "github.com/prebid/prebid-server/v3/adapters/mobkoi" - "github.com/prebid/prebid-server/v3/adapters/motorik" - "github.com/prebid/prebid-server/v3/adapters/msft" - "github.com/prebid/prebid-server/v3/adapters/nativery" - "github.com/prebid/prebid-server/v3/adapters/nativo" - "github.com/prebid/prebid-server/v3/adapters/nextmillennium" - "github.com/prebid/prebid-server/v3/adapters/nexx360" - "github.com/prebid/prebid-server/v3/adapters/nobid" - "github.com/prebid/prebid-server/v3/adapters/ogury" - "github.com/prebid/prebid-server/v3/adapters/oms" - "github.com/prebid/prebid-server/v3/adapters/onetag" - "github.com/prebid/prebid-server/v3/adapters/openweb" - "github.com/prebid/prebid-server/v3/adapters/openx" - "github.com/prebid/prebid-server/v3/adapters/operaads" - "github.com/prebid/prebid-server/v3/adapters/optidigital" - "github.com/prebid/prebid-server/v3/adapters/oraki" - "github.com/prebid/prebid-server/v3/adapters/orbidder" - "github.com/prebid/prebid-server/v3/adapters/outbrain" - "github.com/prebid/prebid-server/v3/adapters/ownadx" - "github.com/prebid/prebid-server/v3/adapters/pangle" - "github.com/prebid/prebid-server/v3/adapters/pgamssp" - "github.com/prebid/prebid-server/v3/adapters/playdigo" - "github.com/prebid/prebid-server/v3/adapters/pubmatic" - "github.com/prebid/prebid-server/v3/adapters/pubnative" - "github.com/prebid/prebid-server/v3/adapters/pubrise" - "github.com/prebid/prebid-server/v3/adapters/pulsepoint" - "github.com/prebid/prebid-server/v3/adapters/pwbid" - "github.com/prebid/prebid-server/v3/adapters/qt" - "github.com/prebid/prebid-server/v3/adapters/readpeak" - "github.com/prebid/prebid-server/v3/adapters/rediads" - "github.com/prebid/prebid-server/v3/adapters/relevantdigital" - "github.com/prebid/prebid-server/v3/adapters/resetdigital" - "github.com/prebid/prebid-server/v3/adapters/revcontent" - "github.com/prebid/prebid-server/v3/adapters/richaudience" - "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/rubicon" - salunamedia "github.com/prebid/prebid-server/v3/adapters/sa_lunamedia" - "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" - "github.com/prebid/prebid-server/v3/adapters/seedtag" - "github.com/prebid/prebid-server/v3/adapters/sharethrough" - "github.com/prebid/prebid-server/v3/adapters/showheroes" - "github.com/prebid/prebid-server/v3/adapters/silvermob" - "github.com/prebid/prebid-server/v3/adapters/silverpush" - "github.com/prebid/prebid-server/v3/adapters/smaato" - "github.com/prebid/prebid-server/v3/adapters/smartadserver" - "github.com/prebid/prebid-server/v3/adapters/smarthub" - "github.com/prebid/prebid-server/v3/adapters/smartrtb" - "github.com/prebid/prebid-server/v3/adapters/smartx" - "github.com/prebid/prebid-server/v3/adapters/smartyads" - "github.com/prebid/prebid-server/v3/adapters/smilewanted" - "github.com/prebid/prebid-server/v3/adapters/smoot" - "github.com/prebid/prebid-server/v3/adapters/smrtconnect" - "github.com/prebid/prebid-server/v3/adapters/sonobi" - "github.com/prebid/prebid-server/v3/adapters/sovrn" - "github.com/prebid/prebid-server/v3/adapters/sovrnXsp" - "github.com/prebid/prebid-server/v3/adapters/sparteo" - "github.com/prebid/prebid-server/v3/adapters/sspBC" - "github.com/prebid/prebid-server/v3/adapters/startio" - "github.com/prebid/prebid-server/v3/adapters/stroeerCore" - "github.com/prebid/prebid-server/v3/adapters/taboola" - "github.com/prebid/prebid-server/v3/adapters/tappx" - "github.com/prebid/prebid-server/v3/adapters/teads" - "github.com/prebid/prebid-server/v3/adapters/telaria" - "github.com/prebid/prebid-server/v3/adapters/teqblaze" - "github.com/prebid/prebid-server/v3/adapters/theadx" - "github.com/prebid/prebid-server/v3/adapters/thetradedesk" - "github.com/prebid/prebid-server/v3/adapters/tpmn" - "github.com/prebid/prebid-server/v3/adapters/tradplus" - "github.com/prebid/prebid-server/v3/adapters/trafficgate" - "github.com/prebid/prebid-server/v3/adapters/triplelift" - "github.com/prebid/prebid-server/v3/adapters/triplelift_native" - "github.com/prebid/prebid-server/v3/adapters/trustedstack" - "github.com/prebid/prebid-server/v3/adapters/trustx" - "github.com/prebid/prebid-server/v3/adapters/ucfunnel" - "github.com/prebid/prebid-server/v3/adapters/undertone" - "github.com/prebid/prebid-server/v3/adapters/unicorn" - "github.com/prebid/prebid-server/v3/adapters/unruly" - "github.com/prebid/prebid-server/v3/adapters/vidazoo" - "github.com/prebid/prebid-server/v3/adapters/videobyte" - "github.com/prebid/prebid-server/v3/adapters/videoheroes" - "github.com/prebid/prebid-server/v3/adapters/vidoomy" - "github.com/prebid/prebid-server/v3/adapters/visiblemeasures" - "github.com/prebid/prebid-server/v3/adapters/visx" - "github.com/prebid/prebid-server/v3/adapters/vox" - "github.com/prebid/prebid-server/v3/adapters/vrtcal" - "github.com/prebid/prebid-server/v3/adapters/vungle" - "github.com/prebid/prebid-server/v3/adapters/xeworks" - "github.com/prebid/prebid-server/v3/adapters/yahooAds" - "github.com/prebid/prebid-server/v3/adapters/yandex" - "github.com/prebid/prebid-server/v3/adapters/yeahmobi" - "github.com/prebid/prebid-server/v3/adapters/yieldlab" - "github.com/prebid/prebid-server/v3/adapters/yieldmo" - "github.com/prebid/prebid-server/v3/adapters/yieldone" - "github.com/prebid/prebid-server/v3/adapters/zentotem" - "github.com/prebid/prebid-server/v3/adapters/zeroclickfraud" - "github.com/prebid/prebid-server/v3/adapters/zeta_global_ssp" - "github.com/prebid/prebid-server/v3/adapters/zmaticoo" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + ttx "github.com/prebid/prebid-server/v4/adapters/33across" + "github.com/prebid/prebid-server/v4/adapters/aax" + "github.com/prebid/prebid-server/v4/adapters/aceex" + "github.com/prebid/prebid-server/v4/adapters/acuityads" + "github.com/prebid/prebid-server/v4/adapters/adagio" + "github.com/prebid/prebid-server/v4/adapters/adelement" + "github.com/prebid/prebid-server/v4/adapters/adf" + "github.com/prebid/prebid-server/v4/adapters/adgeneration" + "github.com/prebid/prebid-server/v4/adapters/adhese" + "github.com/prebid/prebid-server/v4/adapters/adkernel" + "github.com/prebid/prebid-server/v4/adapters/adkernelAdn" + "github.com/prebid/prebid-server/v4/adapters/adman" + "github.com/prebid/prebid-server/v4/adapters/admatic" + "github.com/prebid/prebid-server/v4/adapters/admixer" + "github.com/prebid/prebid-server/v4/adapters/adnuntius" + "github.com/prebid/prebid-server/v4/adapters/adot" + "github.com/prebid/prebid-server/v4/adapters/adpone" + "github.com/prebid/prebid-server/v4/adapters/adprime" + "github.com/prebid/prebid-server/v4/adapters/adquery" + "github.com/prebid/prebid-server/v4/adapters/adrino" + "github.com/prebid/prebid-server/v4/adapters/adtarget" + "github.com/prebid/prebid-server/v4/adapters/adtelligent" + "github.com/prebid/prebid-server/v4/adapters/adtonos" + "github.com/prebid/prebid-server/v4/adapters/adtrgtme" + "github.com/prebid/prebid-server/v4/adapters/aduptech" + "github.com/prebid/prebid-server/v4/adapters/advangelists" + "github.com/prebid/prebid-server/v4/adapters/adverxo" + "github.com/prebid/prebid-server/v4/adapters/adview" + "github.com/prebid/prebid-server/v4/adapters/adxcg" + "github.com/prebid/prebid-server/v4/adapters/adyoulike" + "github.com/prebid/prebid-server/v4/adapters/afront" + "github.com/prebid/prebid-server/v4/adapters/aidem" + "github.com/prebid/prebid-server/v4/adapters/aja" + "github.com/prebid/prebid-server/v4/adapters/akcelo" + "github.com/prebid/prebid-server/v4/adapters/algorix" + "github.com/prebid/prebid-server/v4/adapters/alkimi" + alliance_gravity "github.com/prebid/prebid-server/v4/adapters/alliance_gravity" + "github.com/prebid/prebid-server/v4/adapters/amx" + "github.com/prebid/prebid-server/v4/adapters/apacdex" + "github.com/prebid/prebid-server/v4/adapters/appnexus" + "github.com/prebid/prebid-server/v4/adapters/appush" + "github.com/prebid/prebid-server/v4/adapters/aso" + "github.com/prebid/prebid-server/v4/adapters/audienceNetwork" + "github.com/prebid/prebid-server/v4/adapters/automatad" + "github.com/prebid/prebid-server/v4/adapters/avocet" + "github.com/prebid/prebid-server/v4/adapters/axis" + "github.com/prebid/prebid-server/v4/adapters/axonix" + "github.com/prebid/prebid-server/v4/adapters/beachfront" + "github.com/prebid/prebid-server/v4/adapters/beintoo" + "github.com/prebid/prebid-server/v4/adapters/bematterfull" + "github.com/prebid/prebid-server/v4/adapters/beop" + "github.com/prebid/prebid-server/v4/adapters/between" + "github.com/prebid/prebid-server/v4/adapters/beyondmedia" + "github.com/prebid/prebid-server/v4/adapters/bidmachine" + "github.com/prebid/prebid-server/v4/adapters/bidmatic" + "github.com/prebid/prebid-server/v4/adapters/bidmyadz" + "github.com/prebid/prebid-server/v4/adapters/bidscube" + "github.com/prebid/prebid-server/v4/adapters/bidstack" + "github.com/prebid/prebid-server/v4/adapters/bidtheatre" + "github.com/prebid/prebid-server/v4/adapters/bigoad" + "github.com/prebid/prebid-server/v4/adapters/blasto" + "github.com/prebid/prebid-server/v4/adapters/bliink" + "github.com/prebid/prebid-server/v4/adapters/blis" + "github.com/prebid/prebid-server/v4/adapters/blue" + "github.com/prebid/prebid-server/v4/adapters/bluesea" + "github.com/prebid/prebid-server/v4/adapters/bmtm" + "github.com/prebid/prebid-server/v4/adapters/boldwin" + "github.com/prebid/prebid-server/v4/adapters/boldwin_rapid" + "github.com/prebid/prebid-server/v4/adapters/brave" + "github.com/prebid/prebid-server/v4/adapters/bwx" + cadentaperturemx "github.com/prebid/prebid-server/v4/adapters/cadent_aperture_mx" + "github.com/prebid/prebid-server/v4/adapters/ccx" + "github.com/prebid/prebid-server/v4/adapters/clydo" + "github.com/prebid/prebid-server/v4/adapters/cointraffic" + "github.com/prebid/prebid-server/v4/adapters/coinzilla" + "github.com/prebid/prebid-server/v4/adapters/colossus" + "github.com/prebid/prebid-server/v4/adapters/compass" + "github.com/prebid/prebid-server/v4/adapters/concert" + "github.com/prebid/prebid-server/v4/adapters/connatix" + "github.com/prebid/prebid-server/v4/adapters/connectad" + "github.com/prebid/prebid-server/v4/adapters/consumable" + "github.com/prebid/prebid-server/v4/adapters/contxtful" + "github.com/prebid/prebid-server/v4/adapters/conversant" + "github.com/prebid/prebid-server/v4/adapters/copper6ssp" + "github.com/prebid/prebid-server/v4/adapters/cpmstar" + "github.com/prebid/prebid-server/v4/adapters/criteo" + "github.com/prebid/prebid-server/v4/adapters/cwire" + "github.com/prebid/prebid-server/v4/adapters/datablocks" + "github.com/prebid/prebid-server/v4/adapters/decenterads" + "github.com/prebid/prebid-server/v4/adapters/deepintent" + "github.com/prebid/prebid-server/v4/adapters/definemedia" + "github.com/prebid/prebid-server/v4/adapters/dianomi" + "github.com/prebid/prebid-server/v4/adapters/displayio" + "github.com/prebid/prebid-server/v4/adapters/dmx" + "github.com/prebid/prebid-server/v4/adapters/driftpixel" + evolution "github.com/prebid/prebid-server/v4/adapters/e_volution" + "github.com/prebid/prebid-server/v4/adapters/edge226" + "github.com/prebid/prebid-server/v4/adapters/elementaltv" + "github.com/prebid/prebid-server/v4/adapters/emtv" + "github.com/prebid/prebid-server/v4/adapters/eplanning" + "github.com/prebid/prebid-server/v4/adapters/epom" + "github.com/prebid/prebid-server/v4/adapters/escalax" + "github.com/prebid/prebid-server/v4/adapters/exco" + "github.com/prebid/prebid-server/v4/adapters/feedad" + "github.com/prebid/prebid-server/v4/adapters/flatads" + "github.com/prebid/prebid-server/v4/adapters/flipp" + "github.com/prebid/prebid-server/v4/adapters/freewheelssp" + "github.com/prebid/prebid-server/v4/adapters/frvradn" + "github.com/prebid/prebid-server/v4/adapters/fwssp" + "github.com/prebid/prebid-server/v4/adapters/gamma" + "github.com/prebid/prebid-server/v4/adapters/gamoshi" + "github.com/prebid/prebid-server/v4/adapters/globalsun" + "github.com/prebid/prebid-server/v4/adapters/goldbach" + "github.com/prebid/prebid-server/v4/adapters/grid" + "github.com/prebid/prebid-server/v4/adapters/gumgum" + "github.com/prebid/prebid-server/v4/adapters/huaweiads" + "github.com/prebid/prebid-server/v4/adapters/imds" + "github.com/prebid/prebid-server/v4/adapters/impactify" + "github.com/prebid/prebid-server/v4/adapters/improvedigital" + "github.com/prebid/prebid-server/v4/adapters/infytv" + "github.com/prebid/prebid-server/v4/adapters/inmobi" + "github.com/prebid/prebid-server/v4/adapters/insticator" + "github.com/prebid/prebid-server/v4/adapters/intenze" + "github.com/prebid/prebid-server/v4/adapters/interactiveoffers" + "github.com/prebid/prebid-server/v4/adapters/invibes" + "github.com/prebid/prebid-server/v4/adapters/iqx" + "github.com/prebid/prebid-server/v4/adapters/iqzone" + "github.com/prebid/prebid-server/v4/adapters/ix" + "github.com/prebid/prebid-server/v4/adapters/jixie" + "github.com/prebid/prebid-server/v4/adapters/kargo" + "github.com/prebid/prebid-server/v4/adapters/kayzen" + "github.com/prebid/prebid-server/v4/adapters/kidoz" + "github.com/prebid/prebid-server/v4/adapters/kiviads" + "github.com/prebid/prebid-server/v4/adapters/kobler" + "github.com/prebid/prebid-server/v4/adapters/krushmedia" + "github.com/prebid/prebid-server/v4/adapters/kueezrtb" + "github.com/prebid/prebid-server/v4/adapters/lemmadigital" + "github.com/prebid/prebid-server/v4/adapters/limelightDigital" + lmkiviads "github.com/prebid/prebid-server/v4/adapters/lm_kiviads" + "github.com/prebid/prebid-server/v4/adapters/lockerdome" + "github.com/prebid/prebid-server/v4/adapters/logan" + "github.com/prebid/prebid-server/v4/adapters/logicad" + "github.com/prebid/prebid-server/v4/adapters/loopme" + "github.com/prebid/prebid-server/v4/adapters/loyal" + "github.com/prebid/prebid-server/v4/adapters/lunamedia" + "github.com/prebid/prebid-server/v4/adapters/mabidder" + "github.com/prebid/prebid-server/v4/adapters/madsense" + "github.com/prebid/prebid-server/v4/adapters/madvertise" + "github.com/prebid/prebid-server/v4/adapters/marsmedia" + "github.com/prebid/prebid-server/v4/adapters/mediago" + "github.com/prebid/prebid-server/v4/adapters/medianet" + "github.com/prebid/prebid-server/v4/adapters/mediasquare" + "github.com/prebid/prebid-server/v4/adapters/melozen" + "github.com/prebid/prebid-server/v4/adapters/metax" + "github.com/prebid/prebid-server/v4/adapters/mgid" + "github.com/prebid/prebid-server/v4/adapters/mgidX" + "github.com/prebid/prebid-server/v4/adapters/minutemedia" + "github.com/prebid/prebid-server/v4/adapters/missena" + "github.com/prebid/prebid-server/v4/adapters/mobfoxpb" + "github.com/prebid/prebid-server/v4/adapters/mobilefuse" + "github.com/prebid/prebid-server/v4/adapters/mobkoi" + "github.com/prebid/prebid-server/v4/adapters/motorik" + "github.com/prebid/prebid-server/v4/adapters/msft" + "github.com/prebid/prebid-server/v4/adapters/nativery" + "github.com/prebid/prebid-server/v4/adapters/nativo" + "github.com/prebid/prebid-server/v4/adapters/nextmillennium" + "github.com/prebid/prebid-server/v4/adapters/nexx360" + "github.com/prebid/prebid-server/v4/adapters/nobid" + "github.com/prebid/prebid-server/v4/adapters/ogury" + "github.com/prebid/prebid-server/v4/adapters/oms" + "github.com/prebid/prebid-server/v4/adapters/onetag" + "github.com/prebid/prebid-server/v4/adapters/openweb" + "github.com/prebid/prebid-server/v4/adapters/openx" + "github.com/prebid/prebid-server/v4/adapters/operaads" + "github.com/prebid/prebid-server/v4/adapters/optidigital" + "github.com/prebid/prebid-server/v4/adapters/oraki" + "github.com/prebid/prebid-server/v4/adapters/orbidder" + "github.com/prebid/prebid-server/v4/adapters/outbrain" + "github.com/prebid/prebid-server/v4/adapters/ownadx" + "github.com/prebid/prebid-server/v4/adapters/pangle" + "github.com/prebid/prebid-server/v4/adapters/pgamssp" + "github.com/prebid/prebid-server/v4/adapters/playdigo" + "github.com/prebid/prebid-server/v4/adapters/pubmatic" + "github.com/prebid/prebid-server/v4/adapters/pubnative" + "github.com/prebid/prebid-server/v4/adapters/pubrise" + "github.com/prebid/prebid-server/v4/adapters/pulsepoint" + "github.com/prebid/prebid-server/v4/adapters/pwbid" + "github.com/prebid/prebid-server/v4/adapters/qt" + "github.com/prebid/prebid-server/v4/adapters/readpeak" + "github.com/prebid/prebid-server/v4/adapters/rediads" + "github.com/prebid/prebid-server/v4/adapters/relevantdigital" + "github.com/prebid/prebid-server/v4/adapters/resetdigital" + "github.com/prebid/prebid-server/v4/adapters/revcontent" + "github.com/prebid/prebid-server/v4/adapters/richaudience" + "github.com/prebid/prebid-server/v4/adapters/rise" + "github.com/prebid/prebid-server/v4/adapters/roulax" + "github.com/prebid/prebid-server/v4/adapters/rtbhouse" + "github.com/prebid/prebid-server/v4/adapters/rubicon" + salunamedia "github.com/prebid/prebid-server/v4/adapters/sa_lunamedia" + "github.com/prebid/prebid-server/v4/adapters/seedingAlliance" + "github.com/prebid/prebid-server/v4/adapters/seedtag" + "github.com/prebid/prebid-server/v4/adapters/sharethrough" + "github.com/prebid/prebid-server/v4/adapters/showheroes" + "github.com/prebid/prebid-server/v4/adapters/silvermob" + "github.com/prebid/prebid-server/v4/adapters/silverpush" + "github.com/prebid/prebid-server/v4/adapters/smaato" + "github.com/prebid/prebid-server/v4/adapters/smartadserver" + "github.com/prebid/prebid-server/v4/adapters/smarthub" + "github.com/prebid/prebid-server/v4/adapters/smartrtb" + "github.com/prebid/prebid-server/v4/adapters/smartx" + "github.com/prebid/prebid-server/v4/adapters/smartyads" + "github.com/prebid/prebid-server/v4/adapters/smilewanted" + "github.com/prebid/prebid-server/v4/adapters/smoot" + "github.com/prebid/prebid-server/v4/adapters/smrtconnect" + "github.com/prebid/prebid-server/v4/adapters/sonobi" + "github.com/prebid/prebid-server/v4/adapters/sovrn" + "github.com/prebid/prebid-server/v4/adapters/sovrnXsp" + "github.com/prebid/prebid-server/v4/adapters/sparteo" + "github.com/prebid/prebid-server/v4/adapters/sspBC" + "github.com/prebid/prebid-server/v4/adapters/startio" + "github.com/prebid/prebid-server/v4/adapters/stroeerCore" + "github.com/prebid/prebid-server/v4/adapters/taboola" + "github.com/prebid/prebid-server/v4/adapters/tappx" + "github.com/prebid/prebid-server/v4/adapters/teads" + "github.com/prebid/prebid-server/v4/adapters/telaria" + "github.com/prebid/prebid-server/v4/adapters/teqblaze" + "github.com/prebid/prebid-server/v4/adapters/theadx" + "github.com/prebid/prebid-server/v4/adapters/thetradedesk" + "github.com/prebid/prebid-server/v4/adapters/tpmn" + "github.com/prebid/prebid-server/v4/adapters/tradplus" + "github.com/prebid/prebid-server/v4/adapters/trafficgate" + "github.com/prebid/prebid-server/v4/adapters/triplelift" + "github.com/prebid/prebid-server/v4/adapters/triplelift_native" + "github.com/prebid/prebid-server/v4/adapters/trustedstack" + "github.com/prebid/prebid-server/v4/adapters/trustx" + "github.com/prebid/prebid-server/v4/adapters/ucfunnel" + "github.com/prebid/prebid-server/v4/adapters/undertone" + "github.com/prebid/prebid-server/v4/adapters/unicorn" + "github.com/prebid/prebid-server/v4/adapters/unruly" + "github.com/prebid/prebid-server/v4/adapters/vidazoo" + "github.com/prebid/prebid-server/v4/adapters/videobyte" + "github.com/prebid/prebid-server/v4/adapters/videoheroes" + "github.com/prebid/prebid-server/v4/adapters/vidoomy" + "github.com/prebid/prebid-server/v4/adapters/visiblemeasures" + "github.com/prebid/prebid-server/v4/adapters/visx" + "github.com/prebid/prebid-server/v4/adapters/vox" + "github.com/prebid/prebid-server/v4/adapters/vrtcal" + "github.com/prebid/prebid-server/v4/adapters/vungle" + "github.com/prebid/prebid-server/v4/adapters/xeworks" + "github.com/prebid/prebid-server/v4/adapters/yahooAds" + "github.com/prebid/prebid-server/v4/adapters/yandex" + "github.com/prebid/prebid-server/v4/adapters/yeahmobi" + "github.com/prebid/prebid-server/v4/adapters/yieldlab" + "github.com/prebid/prebid-server/v4/adapters/yieldmo" + "github.com/prebid/prebid-server/v4/adapters/yieldone" + "github.com/prebid/prebid-server/v4/adapters/zentotem" + "github.com/prebid/prebid-server/v4/adapters/zeroclickfraud" + "github.com/prebid/prebid-server/v4/adapters/zeta_global_ssp" + "github.com/prebid/prebid-server/v4/adapters/zmaticoo" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Adapter registration is kept in this separate file for ease of use and to aid diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 05487fe278..bddbaed5fc 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -5,10 +5,10 @@ import ( "net/http" "strings" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func BuildAdapters(client *http.Client, cfg *config.Configuration, infos config.BidderInfos, me metrics.MetricsEngine) (map[openrtb_ext.BidderName]AdaptedBidder, map[openrtb_ext.BidderName]struct{}, []error) { diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go index 9827758356..cf06957d8c 100644 --- a/exchange/adapter_util_test.go +++ b/exchange/adapter_util_test.go @@ -6,12 +6,12 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adapters/appnexus" - "github.com/prebid/prebid-server/v3/adapters/rubicon" - "github.com/prebid/prebid-server/v3/config" - metrics "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/appnexus" + "github.com/prebid/prebid-server/v4/adapters/rubicon" + "github.com/prebid/prebid-server/v4/config" + metrics "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/exchange/auction.go b/exchange/auction.go index ff1e28302c..6a5cc8b280 100644 --- a/exchange/auction.go +++ b/exchange/auction.go @@ -12,11 +12,11 @@ import ( uuid "github.com/gofrs/uuid" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const ( diff --git a/exchange/auction_response.go b/exchange/auction_response.go index 67ab2dc4bb..592e89eaa6 100644 --- a/exchange/auction_response.go +++ b/exchange/auction_response.go @@ -2,7 +2,7 @@ package exchange import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // AuctionResponse contains OpenRTB Bid Response object and its extension (un-marshalled) object diff --git a/exchange/auction_test.go b/exchange/auction_test.go index 188e4d30ea..95ee6d3710 100644 --- a/exchange/auction_test.go +++ b/exchange/auction_test.go @@ -12,12 +12,12 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/exchange/bidder.go b/exchange/bidder.go index 264a03d46e..e96fdc1a89 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -19,25 +19,25 @@ import ( "sync/atomic" "time" - "github.com/prebid/prebid-server/v3/bidadjustment" - "github.com/prebid/prebid-server/v3/config/util" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - loggerI "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/version" + "github.com/prebid/prebid-server/v4/bidadjustment" + "github.com/prebid/prebid-server/v4/config/util" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + loggerI "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/version" "github.com/prebid/openrtb/v20/adcom1" nativeRequests "github.com/prebid/openrtb/v20/native1/request" nativeResponse "github.com/prebid/openrtb/v20/native1/response" "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/metrics" - "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/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "golang.org/x/net/context/ctxhttp" ) diff --git a/exchange/bidder_health_test.go b/exchange/bidder_health_test.go index 1fa7748923..0bf46b5afc 100644 --- a/exchange/bidder_health_test.go +++ b/exchange/bidder_health_test.go @@ -6,9 +6,9 @@ import ( "sync" "testing" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index eb061ee691..3fd7f51300 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -25,20 +25,20 @@ import ( nativeRequests "github.com/prebid/openrtb/v20/native1/request" nativeResponse "github.com/prebid/openrtb/v20/native1/response" "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/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/version" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/exchange/bidder_validate_bids.go b/exchange/bidder_validate_bids.go index 5c5da548cb..c4541a3a7d 100644 --- a/exchange/bidder_validate_bids.go +++ b/exchange/bidder_validate_bids.go @@ -7,12 +7,12 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/openrtb_ext" goCurrency "golang.org/x/text/currency" ) diff --git a/exchange/bidder_validate_bids_test.go b/exchange/bidder_validate_bids_test.go index b611ca8175..777c0a504f 100644 --- a/exchange/bidder_validate_bids_test.go +++ b/exchange/bidder_validate_bids_test.go @@ -5,12 +5,12 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/exchange/entities/entities.go b/exchange/entities/entities.go index 808125f1c1..cb5b6c4cdf 100644 --- a/exchange/entities/entities.go +++ b/exchange/entities/entities.go @@ -2,7 +2,7 @@ package entities import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // PbsOrtbSeatBid is a SeatBid returned by an AdaptedBidder. diff --git a/exchange/events.go b/exchange/events.go index 20150f90b9..75334f6c5d 100644 --- a/exchange/events.go +++ b/exchange/events.go @@ -3,14 +3,14 @@ package exchange import ( "time" - "github.com/prebid/prebid-server/v3/exchange/entities" + "github.com/prebid/prebid-server/v4/exchange/entities" jsonpatch "gopkg.in/evanphx/json-patch.v5" - "github.com/prebid/prebid-server/v3/analytics" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/endpoints/events" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/analytics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/endpoints/events" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // eventTracking has configuration fields needed for adding event tracking to an auction response diff --git a/exchange/events_test.go b/exchange/events_test.go index 3f35ef517d..e8ac475150 100644 --- a/exchange/events_test.go +++ b/exchange/events_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/exchange/exchange.go b/exchange/exchange.go index ef24e3fc9c..1452c04928 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -14,31 +14,31 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/adservertargeting" - "github.com/prebid/prebid-server/v3/bidadjustment" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/dsa" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/firstpartydata" - "github.com/prebid/prebid-server/v3/floors" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/maputil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adservertargeting" + "github.com/prebid/prebid-server/v4/bidadjustment" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/dsa" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/firstpartydata" + "github.com/prebid/prebid-server/v4/floors" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/maputil" "github.com/buger/jsonparser" "github.com/gofrs/uuid" diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index 0a41e6ac0f..c18ebd5af9 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -20,30 +20,30 @@ import ( "github.com/buger/jsonparser" "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/currency" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - metricsConf "github.com/prebid/prebid-server/v3/metrics/config" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - pbc "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/file_fetcher" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + metricsConf "github.com/prebid/prebid-server/v4/metrics/config" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + pbc "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/file_fetcher" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" jsonpatch "gopkg.in/evanphx/json-patch.v5" diff --git a/exchange/non_bid_reason.go b/exchange/non_bid_reason.go index 05d4ea3ee6..04f18d9c86 100644 --- a/exchange/non_bid_reason.go +++ b/exchange/non_bid_reason.go @@ -5,7 +5,7 @@ import ( "net" "syscall" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) // SeatNonBid list the reasons why bid was not resulted in positive bid diff --git a/exchange/non_bid_reason_test.go b/exchange/non_bid_reason_test.go index fb9c5e434f..5c30dde969 100644 --- a/exchange/non_bid_reason_test.go +++ b/exchange/non_bid_reason_test.go @@ -6,7 +6,7 @@ import ( "syscall" "testing" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" "github.com/stretchr/testify/assert" ) diff --git a/exchange/price_granularity.go b/exchange/price_granularity.go index b1d5073cd3..d471085dbb 100644 --- a/exchange/price_granularity.go +++ b/exchange/price_granularity.go @@ -6,8 +6,8 @@ import ( "strconv" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // GetPriceBucket is the externally facing function for computing CPM buckets diff --git a/exchange/price_granularity_test.go b/exchange/price_granularity_test.go index 277696b88d..ca18d7ae78 100644 --- a/exchange/price_granularity_test.go +++ b/exchange/price_granularity_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/exchange/seat_non_bids.go b/exchange/seat_non_bids.go index fd6fd1da3f..d62dcb7f81 100644 --- a/exchange/seat_non_bids.go +++ b/exchange/seat_non_bids.go @@ -1,8 +1,8 @@ package exchange import ( - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type SeatNonBidBuilder map[string][]openrtb_ext.NonBid diff --git a/exchange/seat_non_bids_test.go b/exchange/seat_non_bids_test.go index 4a8f9e8f78..a6ec99fb10 100644 --- a/exchange/seat_non_bids_test.go +++ b/exchange/seat_non_bids_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/exchange/targeting.go b/exchange/targeting.go index d39c2cba0a..468f42d457 100644 --- a/exchange/targeting.go +++ b/exchange/targeting.go @@ -5,7 +5,7 @@ import ( "strconv" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const MaxKeyLength = 20 diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go index 7fe26c4bad..a3625ab3ad 100644 --- a/exchange/targeting_test.go +++ b/exchange/targeting_test.go @@ -8,16 +8,16 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" diff --git a/exchange/tmax_adjustments.go b/exchange/tmax_adjustments.go index 0d0fa31fdc..7fe69b3906 100644 --- a/exchange/tmax_adjustments.go +++ b/exchange/tmax_adjustments.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) type TmaxAdjustmentsPreprocessed struct { diff --git a/exchange/tmax_adjustments_test.go b/exchange/tmax_adjustments_test.go index 7925233987..6a3041c0a5 100644 --- a/exchange/tmax_adjustments_test.go +++ b/exchange/tmax_adjustments_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/exchange/utils.go b/exchange/utils.go index 7606cd4248..12d57d954b 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -13,20 +13,20 @@ import ( gppConstants "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/firstpartydata" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/privacy/ccpa" - "github.com/prebid/prebid-server/v3/privacy/lmt" - "github.com/prebid/prebid-server/v3/schain" - "github.com/prebid/prebid-server/v3/stored_responses" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/firstpartydata" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/privacy/ccpa" + "github.com/prebid/prebid-server/v4/privacy/lmt" + "github.com/prebid/prebid-server/v4/schain" + "github.com/prebid/prebid-server/v4/stored_responses" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) var errInvalidRequestExt = errors.New("request.ext is invalid") diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 3585c71be3..63f1200a94 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -10,15 +10,15 @@ import ( gpplib "github.com/prebid/go-gpp" "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/firstpartydata" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/firstpartydata" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/experiment/adscert/SignerLogger.go b/experiment/adscert/SignerLogger.go index 798e9bd2a1..d2ba706e82 100644 --- a/experiment/adscert/SignerLogger.go +++ b/experiment/adscert/SignerLogger.go @@ -3,7 +3,7 @@ package adscert import ( "fmt" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) type SignerLogger struct { diff --git a/experiment/adscert/inprocesssigner.go b/experiment/adscert/inprocesssigner.go index ee5f4905d2..a8d0ac7244 100644 --- a/experiment/adscert/inprocesssigner.go +++ b/experiment/adscert/inprocesssigner.go @@ -8,7 +8,7 @@ import ( "github.com/IABTechLab/adscert/pkg/adscert/discovery" "github.com/IABTechLab/adscert/pkg/adscert/signatory" "github.com/benbjohnson/clock" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) // inProcessSigner holds the signatory to add adsCert header to requests using in process go library diff --git a/experiment/adscert/remotesigner.go b/experiment/adscert/remotesigner.go index c441bbebb6..0576d39976 100644 --- a/experiment/adscert/remotesigner.go +++ b/experiment/adscert/remotesigner.go @@ -6,7 +6,7 @@ import ( "github.com/IABTechLab/adscert/pkg/adscert/api" "github.com/IABTechLab/adscert/pkg/adscert/signatory" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) diff --git a/experiment/adscert/signer.go b/experiment/adscert/signer.go index f7ea9a4254..44003cd88c 100644 --- a/experiment/adscert/signer.go +++ b/experiment/adscert/signer.go @@ -6,7 +6,7 @@ import ( "github.com/IABTechLab/adscert/pkg/adscert/api" "github.com/IABTechLab/adscert/pkg/adscert/logger" "github.com/IABTechLab/adscert/pkg/adscert/signatory" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) const SignHeader = "X-Ads-Cert-Auth" diff --git a/experiment/adscert/signer_test.go b/experiment/adscert/signer_test.go index 3e08d0f6ba..596922be34 100644 --- a/experiment/adscert/signer_test.go +++ b/experiment/adscert/signer_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/IABTechLab/adscert/pkg/adscert/api" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/firstpartydata/first_party_data.go b/firstpartydata/first_party_data.go index c91a0689b8..44a451600a 100644 --- a/firstpartydata/first_party_data.go +++ b/firstpartydata/first_party_data.go @@ -9,10 +9,10 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" jsonpatch "gopkg.in/evanphx/json-patch.v5" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) var ( diff --git a/firstpartydata/first_party_data_test.go b/firstpartydata/first_party_data_test.go index 3e4ff174ee..ef88e79a59 100644 --- a/firstpartydata/first_party_data_test.go +++ b/firstpartydata/first_party_data_test.go @@ -8,9 +8,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/floors/enforce.go b/floors/enforce.go index f72d2bb72c..f55d80e07c 100644 --- a/floors/enforce.go +++ b/floors/enforce.go @@ -6,10 +6,10 @@ import ( "math/rand" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Enforce does floors enforcement for bids from all bidders based on floors provided in request, account level floors config diff --git a/floors/enforce_test.go b/floors/enforce_test.go index 3da86e2d74..c839188d7b 100644 --- a/floors/enforce_test.go +++ b/floors/enforce_test.go @@ -7,11 +7,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/floors/fetcher.go b/floors/fetcher.go index c3d2a02f78..ac62931a39 100644 --- a/floors/fetcher.go +++ b/floors/fetcher.go @@ -14,11 +14,11 @@ import ( "github.com/alitto/pond" validator "github.com/asaskevich/govalidator" "github.com/coocood/freecache" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/timeutil" ) var refetchCheckInterval = 300 diff --git a/floors/fetcher_test.go b/floors/fetcher_test.go index 83876dc48b..41bff4e2ad 100644 --- a/floors/fetcher_test.go +++ b/floors/fetcher_test.go @@ -12,12 +12,12 @@ import ( "github.com/alitto/pond" "github.com/coocood/freecache" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - metricsConf "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + metricsConf "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/timeutil" "github.com/stretchr/testify/assert" ) diff --git a/floors/floors.go b/floors/floors.go index 5bcd2e5e62..658bf756ec 100644 --- a/floors/floors.go +++ b/floors/floors.go @@ -6,10 +6,10 @@ import ( "math/rand" "strings" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type Price struct { diff --git a/floors/floors_test.go b/floors/floors_test.go index 8d73a5de0a..fecdad24c5 100644 --- a/floors/floors_test.go +++ b/floors/floors_test.go @@ -7,11 +7,11 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/floors/rule.go b/floors/rule.go index fb3130c609..4e85328878 100644 --- a/floors/rule.go +++ b/floors/rule.go @@ -8,10 +8,10 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const ( diff --git a/floors/rule_test.go b/floors/rule_test.go index dc46e05993..d5d65f0e2f 100644 --- a/floors/rule_test.go +++ b/floors/rule_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/floors/validate.go b/floors/validate.go index 140df7def3..74db164062 100644 --- a/floors/validate.go +++ b/floors/validate.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) var validSchemaDimensions = map[string]struct{}{ diff --git a/floors/validate_test.go b/floors/validate_test.go index 36c1c73e0b..37418ea5eb 100644 --- a/floors/validate_test.go +++ b/floors/validate_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/aggregated_config.go b/gdpr/aggregated_config.go index 3df5fdc7ff..c0f40f4a6d 100644 --- a/gdpr/aggregated_config.go +++ b/gdpr/aggregated_config.go @@ -3,8 +3,8 @@ package gdpr import ( "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // TCF2ConfigReader is an interface to access TCF2 configurations diff --git a/gdpr/aggregated_config_test.go b/gdpr/aggregated_config_test.go index f577772cb6..44cd07efcf 100644 --- a/gdpr/aggregated_config_test.go +++ b/gdpr/aggregated_config_test.go @@ -5,8 +5,8 @@ import ( "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/basic_enforcement_test.go b/gdpr/basic_enforcement_test.go index 7bb0076940..b4ed2aeb3d 100644 --- a/gdpr/basic_enforcement_test.go +++ b/gdpr/basic_enforcement_test.go @@ -6,7 +6,7 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/go-gdpr/vendorconsent" tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/full_enforcement_test.go b/gdpr/full_enforcement_test.go index eed86bf238..10c8463f37 100644 --- a/gdpr/full_enforcement_test.go +++ b/gdpr/full_enforcement_test.go @@ -8,8 +8,8 @@ import ( tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go index d8cd56fe41..633741a752 100644 --- a/gdpr/gdpr.go +++ b/gdpr/gdpr.go @@ -3,9 +3,9 @@ package gdpr import ( "context" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type Permissions interface { diff --git a/gdpr/gdpr_test.go b/gdpr/gdpr_test.go index 01e829ebfc..6670fc6849 100644 --- a/gdpr/gdpr_test.go +++ b/gdpr/gdpr_test.go @@ -6,9 +6,9 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/go-gdpr/vendorlist" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/gvl_vendor_ids.go b/gdpr/gvl_vendor_ids.go index 401642c56a..bcec2db517 100644 --- a/gdpr/gvl_vendor_ids.go +++ b/gdpr/gvl_vendor_ids.go @@ -8,9 +8,9 @@ import ( "sync/atomic" "time" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/util/task" "golang.org/x/net/context/ctxhttp" ) diff --git a/gdpr/gvl_vendor_ids_test.go b/gdpr/gvl_vendor_ids_test.go index d9974176b8..43010df578 100644 --- a/gdpr/gvl_vendor_ids_test.go +++ b/gdpr/gvl_vendor_ids_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/metrics" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/impl.go b/gdpr/impl.go index 386ce3517b..03c0e234b3 100644 --- a/gdpr/impl.go +++ b/gdpr/impl.go @@ -6,8 +6,8 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/consentconstants" tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const noBidder openrtb_ext.BidderName = "" diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go index ac993f25c1..ec62f73108 100644 --- a/gdpr/impl_test.go +++ b/gdpr/impl_test.go @@ -9,9 +9,9 @@ import ( "github.com/prebid/go-gdpr/consentconstants" "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/purpose_config.go b/gdpr/purpose_config.go index 020d0aaa06..9838c873f1 100644 --- a/gdpr/purpose_config.go +++ b/gdpr/purpose_config.go @@ -2,7 +2,7 @@ package gdpr import ( "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) // purposeConfig represents all of the config info selected from the host and account configs for diff --git a/gdpr/purpose_config_test.go b/gdpr/purpose_config_test.go index 61b7b9b2d6..025019ea0b 100644 --- a/gdpr/purpose_config_test.go +++ b/gdpr/purpose_config_test.go @@ -3,7 +3,7 @@ package gdpr import ( "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/purpose_enforcer.go b/gdpr/purpose_enforcer.go index 5cc5d8e83d..28a0c6dcd1 100644 --- a/gdpr/purpose_enforcer.go +++ b/gdpr/purpose_enforcer.go @@ -4,8 +4,8 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/consentconstants" tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // PurposeEnforcer represents the enforcement strategy for determining if legal basis is achieved for a purpose diff --git a/gdpr/purpose_enforcer_test.go b/gdpr/purpose_enforcer_test.go index 756bb07d71..a73f6b3ee8 100644 --- a/gdpr/purpose_enforcer_test.go +++ b/gdpr/purpose_enforcer_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/signal.go b/gdpr/signal.go index 478985b64f..b8bb49c27f 100644 --- a/gdpr/signal.go +++ b/gdpr/signal.go @@ -3,7 +3,7 @@ package gdpr import ( "strconv" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) type Signal int diff --git a/gdpr/utils.go b/gdpr/utils.go index 543b70a4b5..a8efc30872 100644 --- a/gdpr/utils.go +++ b/gdpr/utils.go @@ -7,8 +7,8 @@ import ( gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" - "github.com/prebid/prebid-server/v3/openrtb_ext" - gppPolicy "github.com/prebid/prebid-server/v3/privacy/gpp" + "github.com/prebid/prebid-server/v4/openrtb_ext" + gppPolicy "github.com/prebid/prebid-server/v4/privacy/gpp" ) // GetGDPR will pull the gdpr flag from an openrtb request diff --git a/gdpr/utils_test.go b/gdpr/utils_test.go index 01fae95de3..747b550db3 100644 --- a/gdpr/utils_test.go +++ b/gdpr/utils_test.go @@ -6,8 +6,8 @@ import ( gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/gdpr/vendorlist-fetching.go b/gdpr/vendorlist-fetching.go index c97c2bdb75..4632c5d6b0 100644 --- a/gdpr/vendorlist-fetching.go +++ b/gdpr/vendorlist-fetching.go @@ -13,9 +13,9 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/vendorlist" "github.com/prebid/go-gdpr/vendorlist2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" "golang.org/x/net/context/ctxhttp" ) diff --git a/gdpr/vendorlist-fetching_test.go b/gdpr/vendorlist-fetching_test.go index 4ba228244b..8a587bd7f2 100644 --- a/gdpr/vendorlist-fetching_test.go +++ b/gdpr/vendorlist-fetching_test.go @@ -11,9 +11,9 @@ import ( "github.com/prebid/go-gdpr/api" "github.com/prebid/go-gdpr/consentconstants" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func TestFetcherDynamicLoadListExists(t *testing.T) { diff --git a/go.mod b/go.mod index fd9bb2b396..ec92fd3eed 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,7 @@ -module github.com/prebid/prebid-server/v3 +module github.com/prebid/prebid-server/v4 go 1.23.0 -retract v3.0.0 // Forgot to update major version in import path and module name - require ( github.com/51Degrees/device-detection-go/v4 v4.4.35 github.com/DATA-DOG/go-sqlmock v1.5.0 diff --git a/hooks/empty_plan.go b/hooks/empty_plan.go index ea86a31405..a26bf8feb4 100644 --- a/hooks/empty_plan.go +++ b/hooks/empty_plan.go @@ -1,8 +1,8 @@ package hooks import ( - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) // EmptyPlanBuilder implements the ExecutionPlanBuilder interface diff --git a/hooks/hookanalytics/analytics_test.go b/hooks/hookanalytics/analytics_test.go index a1186e1b86..3f783d4b27 100644 --- a/hooks/hookanalytics/analytics_test.go +++ b/hooks/hookanalytics/analytics_test.go @@ -3,7 +3,7 @@ package hookanalytics import ( "testing" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/hooks/hookexecution/context.go b/hooks/hookexecution/context.go index 75ad2a8217..fee4e7385a 100644 --- a/hooks/hookexecution/context.go +++ b/hooks/hookexecution/context.go @@ -3,10 +3,10 @@ package hookexecution import ( "sync" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/privacy" ) // executionContext holds information passed to module's hook during hook execution. diff --git a/hooks/hookexecution/enricher.go b/hooks/hookexecution/enricher.go index 17a2eb9cc9..a7043a25a5 100644 --- a/hooks/hookexecution/enricher.go +++ b/hooks/hookexecution/enricher.go @@ -5,8 +5,8 @@ import ( "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/util/jsonutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/hooks/hookexecution/enricher_test.go b/hooks/hookexecution/enricher_test.go index beb07444d1..d25b30b407 100644 --- a/hooks/hookexecution/enricher_test.go +++ b/hooks/hookexecution/enricher_test.go @@ -7,10 +7,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/hooks/hookexecution/errors.go b/hooks/hookexecution/errors.go index 0e61ebc983..c8124d7c02 100644 --- a/hooks/hookexecution/errors.go +++ b/hooks/hookexecution/errors.go @@ -3,7 +3,7 @@ package hookexecution import ( "fmt" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) // TimeoutError indicates exceeding of the max execution time allotted for hook. diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go index 57a145dd1c..cb5b49c70c 100644 --- a/hooks/hookexecution/execution.go +++ b/hooks/hookexecution/execution.go @@ -8,15 +8,15 @@ import ( "sync" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/util/iputil" ) type hookResponse[T any] struct { diff --git a/hooks/hookexecution/execution_test.go b/hooks/hookexecution/execution_test.go index 1090db578d..5c3dd72943 100644 --- a/hooks/hookexecution/execution_test.go +++ b/hooks/hookexecution/execution_test.go @@ -4,10 +4,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" "github.com/stretchr/testify/assert" ) diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go index 0e5b28fff8..c33cfcdda5 100644 --- a/hooks/hookexecution/executor.go +++ b/hooks/hookexecution/executor.go @@ -6,14 +6,14 @@ import ( "sync" "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/exchange/entities" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" ) const ( diff --git a/hooks/hookexecution/executor_test.go b/hooks/hookexecution/executor_test.go index 4ce9933c83..dd309dffa9 100644 --- a/hooks/hookexecution/executor_test.go +++ b/hooks/hookexecution/executor_test.go @@ -10,17 +10,17 @@ import ( "time" "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/exchange/entities" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/metrics" - metricsConfig "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/privacy" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/metrics" + metricsConfig "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/privacy" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go index 3d9d982861..cb3c95b9d1 100644 --- a/hooks/hookexecution/mocks_test.go +++ b/hooks/hookexecution/mocks_test.go @@ -6,9 +6,9 @@ import ( "time" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type mockUpdateHeaderEntrypointHook struct{} diff --git a/hooks/hookexecution/outcome.go b/hooks/hookexecution/outcome.go index d17d3cd467..b9c2561328 100644 --- a/hooks/hookexecution/outcome.go +++ b/hooks/hookexecution/outcome.go @@ -3,7 +3,7 @@ package hookexecution import ( "time" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" ) // Status indicates the result of hook execution. diff --git a/hooks/hookexecution/test_utils.go b/hooks/hookexecution/test_utils.go index b26d4aae4b..cd4f4d16ff 100644 --- a/hooks/hookexecution/test_utils.go +++ b/hooks/hookexecution/test_utils.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/hooks/hookstage/allprocessedbidresponses.go b/hooks/hookstage/allprocessedbidresponses.go index 6bfe0d8082..09b4860261 100644 --- a/hooks/hookstage/allprocessedbidresponses.go +++ b/hooks/hookstage/allprocessedbidresponses.go @@ -3,8 +3,8 @@ package hookstage import ( "context" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // AllProcessedBidResponses hooks are invoked over a list of all diff --git a/hooks/hookstage/bidderrequest.go b/hooks/hookstage/bidderrequest.go index 8c27f07242..ab06ad97a6 100644 --- a/hooks/hookstage/bidderrequest.go +++ b/hooks/hookstage/bidderrequest.go @@ -3,7 +3,7 @@ package hookstage import ( "context" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // BidderRequest hooks are invoked for each bidder participating in auction. diff --git a/hooks/hookstage/bidderrequest_mutations.go b/hooks/hookstage/bidderrequest_mutations.go index 3ab571ff8e..946f5b92c9 100644 --- a/hooks/hookstage/bidderrequest_mutations.go +++ b/hooks/hookstage/bidderrequest_mutations.go @@ -3,7 +3,7 @@ package hookstage import ( "errors" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/openrtb/v20/adcom1" ) diff --git a/hooks/hookstage/invocation.go b/hooks/hookstage/invocation.go index b5452af7fc..ee2f2ec89a 100644 --- a/hooks/hookstage/invocation.go +++ b/hooks/hookstage/invocation.go @@ -3,7 +3,7 @@ package hookstage import ( "encoding/json" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" ) // HookResult represents the result of execution the concrete hook instance. diff --git a/hooks/hookstage/processedauctionrequest.go b/hooks/hookstage/processedauctionrequest.go index 0674213882..deb2994ab5 100644 --- a/hooks/hookstage/processedauctionrequest.go +++ b/hooks/hookstage/processedauctionrequest.go @@ -3,7 +3,7 @@ package hookstage import ( "context" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // ProcessedAuctionRequest hooks are invoked after the request is parsed diff --git a/hooks/hookstage/processedauctionrequest_mutations.go b/hooks/hookstage/processedauctionrequest_mutations.go index 9cd9c64573..a98cbbc580 100644 --- a/hooks/hookstage/processedauctionrequest_mutations.go +++ b/hooks/hookstage/processedauctionrequest_mutations.go @@ -3,7 +3,7 @@ package hookstage import ( "encoding/json" "errors" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func (c *ChangeSet[T]) ProcessedAuctionRequest() ChangeSetProcessedAuctionRequest[T] { diff --git a/hooks/hookstage/processedauctionrequest_mutations_test.go b/hooks/hookstage/processedauctionrequest_mutations_test.go index bf7616a6d3..3bfb94bf0b 100644 --- a/hooks/hookstage/processedauctionrequest_mutations_test.go +++ b/hooks/hookstage/processedauctionrequest_mutations_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/hooks/hookstage/rawbidderresponse.go b/hooks/hookstage/rawbidderresponse.go index 52d1d8a1ba..9299a73600 100644 --- a/hooks/hookstage/rawbidderresponse.go +++ b/hooks/hookstage/rawbidderresponse.go @@ -3,7 +3,7 @@ package hookstage import ( "context" - "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v4/adapters" ) // RawBidderResponse hooks are invoked for each bidder participating in auction. diff --git a/hooks/hookstage/rawbidderresponse_mutations.go b/hooks/hookstage/rawbidderresponse_mutations.go index 027598c651..203f9ac3bc 100644 --- a/hooks/hookstage/rawbidderresponse_mutations.go +++ b/hooks/hookstage/rawbidderresponse_mutations.go @@ -3,7 +3,7 @@ package hookstage import ( "errors" - "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v4/adapters" ) func (c *ChangeSet[T]) RawBidderResponse() ChangeSetRawBidderResponse[T] { diff --git a/hooks/plan.go b/hooks/plan.go index c64dfb1cfb..8324487d37 100644 --- a/hooks/plan.go +++ b/hooks/plan.go @@ -3,9 +3,9 @@ package hooks import ( "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/logger" ) type Stage string diff --git a/hooks/plan_test.go b/hooks/plan_test.go index 3266d2177f..0d7639b583 100644 --- a/hooks/plan_test.go +++ b/hooks/plan_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/hooks/repo.go b/hooks/repo.go index e00077e7bc..e9e545b50b 100644 --- a/hooks/repo.go +++ b/hooks/repo.go @@ -3,7 +3,7 @@ package hooks import ( "fmt" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) // HookRepository is the interface that exposes methods diff --git a/hooks/repo_test.go b/hooks/repo_test.go index d6d3713351..b31554d406 100644 --- a/hooks/repo_test.go +++ b/hooks/repo_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookstage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/injector/injector.go b/injector/injector.go index 9de2c1b726..0df0c2aeaa 100644 --- a/injector/injector.go +++ b/injector/injector.go @@ -6,8 +6,8 @@ import ( "io" "strings" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" ) const ( diff --git a/injector/injector_test.go b/injector/injector_test.go index b3457b094b..4010066228 100644 --- a/injector/injector_test.go +++ b/injector/injector_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/macros/provider.go b/macros/provider.go index 575aa49aa5..fa9b584b4d 100644 --- a/macros/provider.go +++ b/macros/provider.go @@ -5,8 +5,8 @@ import ( "strconv" "time" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const ( diff --git a/macros/provider_test.go b/macros/provider_test.go index 795fae9c41..cc92b0dc78 100644 --- a/macros/provider_test.go +++ b/macros/provider_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/macros/string_index_based_replacer_test.go b/macros/string_index_based_replacer_test.go index 515640d4ff..868592790f 100644 --- a/macros/string_index_based_replacer_test.go +++ b/macros/string_index_based_replacer_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/exchange/entities" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/exchange/entities" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/main.go b/main.go index dbc2d91f10..3870a9b490 100644 --- a/main.go +++ b/main.go @@ -8,14 +8,14 @@ import ( "time" jsoniter "github.com/json-iterator/go" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/router" - "github.com/prebid/prebid-server/v3/server" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/router" + "github.com/prebid/prebid-server/v4/server" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/task" "github.com/spf13/viper" ) diff --git a/main_test.go b/main_test.go index 494e6d6774..92c0b90200 100644 --- a/main_test.go +++ b/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" "github.com/spf13/viper" diff --git a/metrics/config/metrics.go b/metrics/config/metrics.go index 5cbfcd6604..6ef2d552c0 100644 --- a/metrics/config/metrics.go +++ b/metrics/config/metrics.go @@ -3,10 +3,10 @@ package config import ( "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - prometheusmetrics "github.com/prebid/prebid-server/v3/metrics/prometheus" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + prometheusmetrics "github.com/prebid/prebid-server/v4/metrics/prometheus" + "github.com/prebid/prebid-server/v4/openrtb_ext" gometrics "github.com/rcrowley/go-metrics" influxdb "github.com/vrischmann/go-metrics-influxdb" ) diff --git a/metrics/config/metrics_test.go b/metrics/config/metrics_test.go index 48166f07fc..1b35f59b1e 100644 --- a/metrics/config/metrics_test.go +++ b/metrics/config/metrics_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - mainConfig "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + mainConfig "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" gometrics "github.com/rcrowley/go-metrics" ) diff --git a/metrics/go_metrics.go b/metrics/go_metrics.go index b79916b46b..4f10166c17 100644 --- a/metrics/go_metrics.go +++ b/metrics/go_metrics.go @@ -6,9 +6,9 @@ import ( "sync" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/openrtb_ext" metrics "github.com/rcrowley/go-metrics" ) diff --git a/metrics/go_metrics_test.go b/metrics/go_metrics_test.go index 65d8399c8c..553dfba09d 100644 --- a/metrics/go_metrics_test.go +++ b/metrics/go_metrics_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" metrics "github.com/rcrowley/go-metrics" "github.com/stretchr/testify/assert" ) diff --git a/metrics/metrics.go b/metrics/metrics.go index 105d6e8468..aa2e28b7c8 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -3,7 +3,7 @@ package metrics import ( "time" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Labels defines the labels that can be attached to the metrics. diff --git a/metrics/metrics_mock.go b/metrics/metrics_mock.go index b3b6532f35..7cf0af5cc0 100644 --- a/metrics/metrics_mock.go +++ b/metrics/metrics_mock.go @@ -3,7 +3,7 @@ package metrics import ( "time" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/mock" ) diff --git a/metrics/prometheus/preload.go b/metrics/prometheus/preload.go index 7311514760..835d71d4d8 100644 --- a/metrics/prometheus/preload.go +++ b/metrics/prometheus/preload.go @@ -1,8 +1,8 @@ package prometheusmetrics import ( - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prometheus/client_golang/prometheus" ) diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 2278ae8d4b..cd694b67c8 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prometheus/client_golang/prometheus" promCollector "github.com/prometheus/client_golang/prometheus/collectors" ) diff --git a/metrics/prometheus/prometheus_test.go b/metrics/prometheus/prometheus_test.go index 971bc74f6b..c9ca024ef9 100644 --- a/metrics/prometheus/prometheus_test.go +++ b/metrics/prometheus/prometheus_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/stretchr/testify/assert" diff --git a/modules/builder.go b/modules/builder.go index 85a38fd022..034ac16ab5 100644 --- a/modules/builder.go +++ b/modules/builder.go @@ -1,10 +1,10 @@ package modules import ( - fiftyonedegreesDevicedetection "github.com/prebid/prebid-server/v3/modules/fiftyonedegrees/devicedetection" - prebidOrtb2blocking "github.com/prebid/prebid-server/v3/modules/prebid/ortb2blocking" - prebidRulesengine "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine" - scope3Rtd "github.com/prebid/prebid-server/v3/modules/scope3/rtd" + fiftyonedegreesDevicedetection "github.com/prebid/prebid-server/v4/modules/fiftyonedegrees/devicedetection" + prebidOrtb2blocking "github.com/prebid/prebid-server/v4/modules/prebid/ortb2blocking" + prebidRulesengine "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine" + scope3Rtd "github.com/prebid/prebid-server/v4/modules/scope3/rtd" ) // builders returns mapping between module name and its builder diff --git a/modules/fiftyonedegrees/devicedetection/config.go b/modules/fiftyonedegrees/devicedetection/config.go index 3a83030b6d..8037f83ec5 100644 --- a/modules/fiftyonedegrees/devicedetection/config.go +++ b/modules/fiftyonedegrees/devicedetection/config.go @@ -8,7 +8,7 @@ import ( "os" "github.com/51Degrees/device-detection-go/v4/dd" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type config struct { diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go index d16ac64f07..e3c4bca69d 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go @@ -6,7 +6,7 @@ import ( "fmt" "strconv" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) // deviceInfoExtractor is a struct that contains the methods to extract device information diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go index 700f53117d..511b85960b 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go @@ -9,7 +9,7 @@ import ( "github.com/51Degrees/device-detection-go/v4/dd" "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) type defaultEvidenceExtractor struct { diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go index 7dc4fb9790..7e2aa6616d 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/51Degrees/device-detection-go/v4/dd" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookstage" "github.com/stretchr/testify/assert" ) diff --git a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go index 8be51c422d..f1429ef7e1 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go +++ b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go @@ -3,8 +3,8 @@ package devicedetection import ( - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) // handleAuctionEntryPointRequestHook is a hookstage.HookFunc that is used to handle the auction entrypoint request hook. diff --git a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go index acde532eb5..4f5580a5c7 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go +++ b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go @@ -6,8 +6,8 @@ import ( "fmt" "math" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" "github.com/tidwall/gjson" "github.com/tidwall/sjson" ) diff --git a/modules/fiftyonedegrees/devicedetection/module.go b/modules/fiftyonedegrees/devicedetection/module.go index 603f37810d..72c0f60d94 100644 --- a/modules/fiftyonedegrees/devicedetection/module.go +++ b/modules/fiftyonedegrees/devicedetection/module.go @@ -10,8 +10,8 @@ import ( "github.com/51Degrees/device-detection-go/v4/dd" "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" ) func configHashFromConfig(cfg *config) *dd.ConfigHash { diff --git a/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go b/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go index 2f4bce4a99..9aca4faa09 100644 --- a/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go +++ b/modules/fiftyonedegrees/devicedetection/module_no_cgo_test.go @@ -5,7 +5,7 @@ package devicedetection import ( "testing" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/modules/moduledeps" "github.com/stretchr/testify/assert" ) diff --git a/modules/fiftyonedegrees/devicedetection/module_test.go b/modules/fiftyonedegrees/devicedetection/module_test.go index 19595aca4e..5566f8e25a 100644 --- a/modules/fiftyonedegrees/devicedetection/module_test.go +++ b/modules/fiftyonedegrees/devicedetection/module_test.go @@ -12,8 +12,8 @@ import ( "github.com/51Degrees/device-detection-go/v4/dd" "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/modules/fiftyonedegrees/devicedetection/no-cgo.go b/modules/fiftyonedegrees/devicedetection/no-cgo.go index c9ec89eb20..4fe5814f7a 100644 --- a/modules/fiftyonedegrees/devicedetection/no-cgo.go +++ b/modules/fiftyonedegrees/devicedetection/no-cgo.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/modules/moduledeps" ) const errMsg = "fiftyonedegrees should not be enabled unless CGO is enabled" diff --git a/modules/generator/builder.tmpl b/modules/generator/builder.tmpl index 211e0d1e08..ebf49e7615 100644 --- a/modules/generator/builder.tmpl +++ b/modules/generator/builder.tmpl @@ -2,7 +2,7 @@ package modules import ( {{- range $vendor, $modules := .}} {{- range $module := $modules}} - {{$vendor}}{{$module | Title}} "github.com/prebid/prebid-server/v3/modules/{{$vendor}}/{{$module}}" + {{$vendor}}{{$module | Title}} "github.com/prebid/prebid-server/v4/modules/{{$vendor}}/{{$module}}" {{- end}} {{- end}} ) diff --git a/modules/helpers.go b/modules/helpers.go index 9a3c547e0b..a23f2dc122 100644 --- a/modules/helpers.go +++ b/modules/helpers.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) var moduleReplacer = strings.NewReplacer(".", "_", "-", "_") diff --git a/modules/moduledeps/deps.go b/modules/moduledeps/deps.go index a60587e1ef..5d15c4d510 100644 --- a/modules/moduledeps/deps.go +++ b/modules/moduledeps/deps.go @@ -3,7 +3,7 @@ package moduledeps import ( "net/http" - "github.com/prebid/prebid-server/v3/currency" + "github.com/prebid/prebid-server/v4/currency" ) // ModuleDeps provides dependencies that custom modules may need for hooks execution. diff --git a/modules/modules.go b/modules/modules.go index fc2e15e7ef..b7e862570f 100644 --- a/modules/modules.go +++ b/modules/modules.go @@ -4,11 +4,11 @@ import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) //go:generate go run ./generator/buildergen.go diff --git a/modules/modules_test.go b/modules/modules_test.go index cdc573e992..e9a1102efd 100644 --- a/modules/modules_test.go +++ b/modules/modules_test.go @@ -9,10 +9,10 @@ import ( "net/http" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/ortb2blocking/analytics.go b/modules/prebid/ortb2blocking/analytics.go index bab50e3a4e..de2b4db61f 100644 --- a/modules/prebid/ortb2blocking/analytics.go +++ b/modules/prebid/ortb2blocking/analytics.go @@ -1,8 +1,8 @@ package ortb2blocking import ( - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) const enforceBlockingTag = "enforce_blocking" diff --git a/modules/prebid/ortb2blocking/config.go b/modules/prebid/ortb2blocking/config.go index f41180155e..102b895f73 100644 --- a/modules/prebid/ortb2blocking/config.go +++ b/modules/prebid/ortb2blocking/config.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/prebid/openrtb/v20/adcom1" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func newConfig(data json.RawMessage) (config, error) { diff --git a/modules/prebid/ortb2blocking/hook_bidderrequest.go b/modules/prebid/ortb2blocking/hook_bidderrequest.go index cd18de72dc..14abbec43a 100644 --- a/modules/prebid/ortb2blocking/hook_bidderrequest.go +++ b/modules/prebid/ortb2blocking/hook_bidderrequest.go @@ -7,9 +7,9 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func handleBidderRequestHook( diff --git a/modules/prebid/ortb2blocking/hook_bidderrequest_test.go b/modules/prebid/ortb2blocking/hook_bidderrequest_test.go index 5730bd5001..82ad708803 100644 --- a/modules/prebid/ortb2blocking/hook_bidderrequest_test.go +++ b/modules/prebid/ortb2blocking/hook_bidderrequest_test.go @@ -5,9 +5,9 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go index a6ddbdd58c..deeb3b0296 100644 --- a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go +++ b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go @@ -7,9 +7,9 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" ) func handleRawBidderResponseHook( diff --git a/modules/prebid/ortb2blocking/module.go b/modules/prebid/ortb2blocking/module.go index 24ff28df74..e31c7ccb7e 100644 --- a/modules/prebid/ortb2blocking/module.go +++ b/modules/prebid/ortb2blocking/module.go @@ -5,8 +5,8 @@ import ( "encoding/json" "github.com/prebid/openrtb/v20/adcom1" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" ) func Builder(_ json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { diff --git a/modules/prebid/ortb2blocking/module_test.go b/modules/prebid/ortb2blocking/module_test.go index 4159d73f34..7d002d29c8 100644 --- a/modules/prebid/ortb2blocking/module_test.go +++ b/modules/prebid/ortb2blocking/module_test.go @@ -8,12 +8,12 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" - "github.com/prebid/prebid-server/v3/hooks/hookexecution" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/bidder_config_ruleset.go b/modules/prebid/rulesengine/bidder_config_ruleset.go index 888c41c696..59d2c0079b 100644 --- a/modules/prebid/rulesengine/bidder_config_ruleset.go +++ b/modules/prebid/rulesengine/bidder_config_ruleset.go @@ -1,7 +1,7 @@ package rulesengine import ( - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/rules" ) // buildBidderConfigRuleSet builds a dynamic ruleset based on the geoscope annotations in the diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_builder.go b/modules/prebid/rulesengine/bidder_config_ruleset_builder.go index 2fe9b705c6..85eb01753c 100644 --- a/modules/prebid/rulesengine/bidder_config_ruleset_builder.go +++ b/modules/prebid/rulesengine/bidder_config_ruleset_builder.go @@ -6,8 +6,8 @@ import ( "slices" "strings" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/rules" ) type CountryExclusions = map[string][]string diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go b/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go index e9f9743aff..709fe3156b 100644 --- a/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go +++ b/modules/prebid/rulesengine/bidder_config_ruleset_builder_test.go @@ -3,7 +3,7 @@ package rulesengine import ( "testing" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/rules" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/bidder_config_ruleset_test.go b/modules/prebid/rulesengine/bidder_config_ruleset_test.go index 93af63cd21..0813028930 100644 --- a/modules/prebid/rulesengine/bidder_config_ruleset_test.go +++ b/modules/prebid/rulesengine/bidder_config_ruleset_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/rules" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/cache.go b/modules/prebid/rulesengine/cache.go index 1b09abc1c5..2110b0cd6a 100644 --- a/modules/prebid/rulesengine/cache.go +++ b/modules/prebid/rulesengine/cache.go @@ -5,7 +5,7 @@ import ( "sync/atomic" "time" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/util/timeutil" ) type accountID = string diff --git a/modules/prebid/rulesengine/cache_entry.go b/modules/prebid/rulesengine/cache_entry.go index 5b995dd6e7..5f912d1827 100644 --- a/modules/prebid/rulesengine/cache_entry.go +++ b/modules/prebid/rulesengine/cache_entry.go @@ -7,10 +7,10 @@ import ( "errors" "time" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" ) type hash = string diff --git a/modules/prebid/rulesengine/cache_entry_test.go b/modules/prebid/rulesengine/cache_entry_test.go index 481f1a26c0..0b3cb8d7dd 100644 --- a/modules/prebid/rulesengine/cache_entry_test.go +++ b/modules/prebid/rulesengine/cache_entry_test.go @@ -5,10 +5,10 @@ import ( "errors" "testing" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/config/config.go b/modules/prebid/rulesengine/config/config.go index 0dc4bded5d..5654d20441 100644 --- a/modules/prebid/rulesengine/config/config.go +++ b/modules/prebid/rulesengine/config/config.go @@ -7,8 +7,8 @@ import ( "fmt" "path/filepath" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/xeipuuv/gojsonschema" ) diff --git a/modules/prebid/rulesengine/hook_processed_auction.go b/modules/prebid/rulesengine/hook_processed_auction.go index 144b72a943..dad6891353 100644 --- a/modules/prebid/rulesengine/hook_processed_auction.go +++ b/modules/prebid/rulesengine/hook_processed_auction.go @@ -3,9 +3,9 @@ package rulesengine import ( "fmt" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/randomutil" + hs "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/randomutil" ) type RequestWrapper = openrtb_ext.RequestWrapper diff --git a/modules/prebid/rulesengine/hook_processed_auction_test.go b/modules/prebid/rulesengine/hook_processed_auction_test.go index 9cc5fc7f8e..7116644195 100644 --- a/modules/prebid/rulesengine/hook_processed_auction_test.go +++ b/modules/prebid/rulesengine/hook_processed_auction_test.go @@ -2,9 +2,9 @@ package rulesengine import ( "fmt" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" + hs "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" "testing" "github.com/stretchr/testify/assert" diff --git a/modules/prebid/rulesengine/module.go b/modules/prebid/rulesengine/module.go index ca63c763b9..e0a59245ed 100644 --- a/modules/prebid/rulesengine/module.go +++ b/modules/prebid/rulesengine/module.go @@ -8,9 +8,9 @@ import ( "github.com/buger/jsonparser" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" + hs "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" ) // Builder configures the rules engine module initiating an in-memory cache and kicking diff --git a/modules/prebid/rulesengine/module_test.go b/modules/prebid/rulesengine/module_test.go index 2cf2bd59bb..9bffeb8816 100644 --- a/modules/prebid/rulesengine/module_test.go +++ b/modules/prebid/rulesengine/module_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/modules/moduledeps" + "github.com/prebid/prebid-server/v4/modules/moduledeps" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/result_functions.go b/modules/prebid/rulesengine/result_functions.go index 64fe23bc4a..eef632ba5b 100644 --- a/modules/prebid/rulesengine/result_functions.go +++ b/modules/prebid/rulesengine/result_functions.go @@ -5,10 +5,10 @@ import ( "errors" "fmt" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // ProcessedAuctionResultFunc is a type alias for a result function that runs in the processed auction request stage. diff --git a/modules/prebid/rulesengine/result_functions_test.go b/modules/prebid/rulesengine/result_functions_test.go index 1b78471ed1..d452f1d83d 100644 --- a/modules/prebid/rulesengine/result_functions_test.go +++ b/modules/prebid/rulesengine/result_functions_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" + hs "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/tree_builder.go b/modules/prebid/rulesengine/tree_builder.go index 438212f061..c74fc095cd 100644 --- a/modules/prebid/rulesengine/tree_builder.go +++ b/modules/prebid/rulesengine/tree_builder.go @@ -1,8 +1,8 @@ package rulesengine import ( - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/rules" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/rules" ) // treeBuilder is a custom tree builder for the rules engine module. diff --git a/modules/prebid/rulesengine/tree_builder_test.go b/modules/prebid/rulesengine/tree_builder_test.go index 38fc6a9ae5..014c28db90 100644 --- a/modules/prebid/rulesengine/tree_builder_test.go +++ b/modules/prebid/rulesengine/tree_builder_test.go @@ -4,10 +4,10 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/modules/prebid/rulesengine/tree_manager.go b/modules/prebid/rulesengine/tree_manager.go index 35496e7591..6aca08c430 100644 --- a/modules/prebid/rulesengine/tree_manager.go +++ b/modules/prebid/rulesengine/tree_manager.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" "github.com/xeipuuv/gojsonschema" ) diff --git a/modules/prebid/rulesengine/tree_manager_test.go b/modules/prebid/rulesengine/tree_manager_test.go index b397074860..4fe7048c1a 100644 --- a/modules/prebid/rulesengine/tree_manager_test.go +++ b/modules/prebid/rulesengine/tree_manager_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/golang/glog" - "github.com/prebid/prebid-server/v3/modules/prebid/rulesengine/config" + "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/modules/prebid/rulesengine/tree_test.go b/modules/prebid/rulesengine/tree_test.go index 4769a2fc49..f7d4a318b1 100644 --- a/modules/prebid/rulesengine/tree_test.go +++ b/modules/prebid/rulesengine/tree_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - hs "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/rules" + hs "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/rules" "github.com/stretchr/testify/assert" ) diff --git a/modules/scope3/rtd/masking.go b/modules/scope3/rtd/masking.go index d32689dacf..d8123aa20b 100644 --- a/modules/scope3/rtd/masking.go +++ b/modules/scope3/rtd/masking.go @@ -4,8 +4,8 @@ import ( "math" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/iterutil" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/iterutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // maskBidRequest creates a deep copy of the bid request with sensitive fields masked diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go index 9b80534a0c..ab4ac3b459 100644 --- a/modules/scope3/rtd/module.go +++ b/modules/scope3/rtd/module.go @@ -18,12 +18,12 @@ import ( "github.com/coocood/freecache" jsoniter "github.com/json-iterator/go" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks/hookanalytics" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/util/iterutil" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/hooks/hookanalytics" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/util/iterutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/tidwall/sjson" ) diff --git a/modules/scope3/rtd/module_test.go b/modules/scope3/rtd/module_test.go index 041d549f25..a9339d3242 100644 --- a/modules/scope3/rtd/module_test.go +++ b/modules/scope3/rtd/module_test.go @@ -15,10 +15,10 @@ import ( "github.com/coocood/freecache" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/hooks/hookstage" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/modules/shutdown.go b/modules/shutdown.go index ae769ddf5e..d8be00b214 100644 --- a/modules/shutdown.go +++ b/modules/shutdown.go @@ -1,7 +1,7 @@ package modules import ( - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) // Shutdowner is an interface that defines a method for shutting down modules. diff --git a/openrtb_ext/convert_down_test.go b/openrtb_ext/convert_down_test.go index 684ae5cda4..0d295872cd 100644 --- a/openrtb_ext/convert_down_test.go +++ b/openrtb_ext/convert_down_test.go @@ -6,8 +6,8 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/deal_tier.go b/openrtb_ext/deal_tier.go index b0f2675d66..c9818479fd 100644 --- a/openrtb_ext/deal_tier.go +++ b/openrtb_ext/deal_tier.go @@ -2,7 +2,7 @@ package openrtb_ext import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // DealTier defines the configuration of a deal tier. diff --git a/openrtb_ext/deal_tier_test.go b/openrtb_ext/deal_tier_test.go index 6808f90a0d..f85390ed26 100644 --- a/openrtb_ext/deal_tier_test.go +++ b/openrtb_ext/deal_tier_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/device.go b/openrtb_ext/device.go index 2107a3081f..feb362e502 100644 --- a/openrtb_ext/device.go +++ b/openrtb_ext/device.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/buger/jsonparser" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) // PrebidExtKey represents the prebid extension key used in requests diff --git a/openrtb_ext/device_test.go b/openrtb_ext/device_test.go index 52b679fda3..d634876143 100644 --- a/openrtb_ext/device_test.go +++ b/openrtb_ext/device_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/floors.go b/openrtb_ext/floors.go index 1faa629232..93667e7d36 100644 --- a/openrtb_ext/floors.go +++ b/openrtb_ext/floors.go @@ -4,7 +4,7 @@ import ( "maps" "slices" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) // Defines strings for FetchStatus diff --git a/openrtb_ext/floors_test.go b/openrtb_ext/floors_test.go index df7d1e5dc2..e80ba28a03 100644 --- a/openrtb_ext/floors_test.go +++ b/openrtb_ext/floors_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/imp_appnexus.go b/openrtb_ext/imp_appnexus.go index bde37bdc9d..e5c43fcf54 100644 --- a/openrtb_ext/imp_appnexus.go +++ b/openrtb_ext/imp_appnexus.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // ExtImpAppnexus defines the contract for bidrequest.imp[i].ext.prebid.bidder.appnexus diff --git a/openrtb_ext/imp_appnexus_test.go b/openrtb_ext/imp_appnexus_test.go index 52e42d4d53..5cf268a793 100644 --- a/openrtb_ext/imp_appnexus_test.go +++ b/openrtb_ext/imp_appnexus_test.go @@ -3,7 +3,7 @@ package openrtb_ext import ( "testing" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/imp_connectad.go b/openrtb_ext/imp_connectad.go index 4affaed1ea..528636f498 100644 --- a/openrtb_ext/imp_connectad.go +++ b/openrtb_ext/imp_connectad.go @@ -1,6 +1,6 @@ package openrtb_ext -import "github.com/prebid/prebid-server/v3/util/jsonutil" +import "github.com/prebid/prebid-server/v4/util/jsonutil" type ExtImpConnectAd struct { NetworkID jsonutil.StringInt `json:"networkId"` diff --git a/openrtb_ext/imp_freewheelssp.go b/openrtb_ext/imp_freewheelssp.go index 5ed1f62609..78040d7bd6 100644 --- a/openrtb_ext/imp_freewheelssp.go +++ b/openrtb_ext/imp_freewheelssp.go @@ -1,7 +1,7 @@ package openrtb_ext import ( - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type ImpExtFreewheelSSP struct { diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go index 238ef2ff2e..512b7883e8 100644 --- a/openrtb_ext/imp_goldbach.go +++ b/openrtb_ext/imp_goldbach.go @@ -3,7 +3,7 @@ package openrtb_ext import ( "fmt" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type ImpExtGoldbach struct { diff --git a/openrtb_ext/imp_pulsepoint.go b/openrtb_ext/imp_pulsepoint.go index a372e3765c..9be3a36941 100644 --- a/openrtb_ext/imp_pulsepoint.go +++ b/openrtb_ext/imp_pulsepoint.go @@ -1,7 +1,7 @@ package openrtb_ext import ( - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // ExtImpPulsePoint defines the json spec for bidrequest.imp[i].ext.prebid.bidder.pulsepoint diff --git a/openrtb_ext/multibid_test.go b/openrtb_ext/multibid_test.go index 5a55265311..9e8de09d9e 100644 --- a/openrtb_ext/multibid_test.go +++ b/openrtb_ext/multibid_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/regs_test.go b/openrtb_ext/regs_test.go index 064282c1f3..ed998054ac 100644 --- a/openrtb_ext/regs_test.go +++ b/openrtb_ext/regs_test.go @@ -3,7 +3,7 @@ package openrtb_ext import ( "testing" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go index 7f8978e6eb..6d51d42145 100644 --- a/openrtb_ext/request.go +++ b/openrtb_ext/request.go @@ -7,8 +7,8 @@ import ( "slices" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) // FirstPartyDataExtKey defines a field name within request.ext and request.imp.ext reserved for first party data. diff --git a/openrtb_ext/request_test.go b/openrtb_ext/request_test.go index 92f148db40..b0c09f6c55 100644 --- a/openrtb_ext/request_test.go +++ b/openrtb_ext/request_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/request_wrapper.go b/openrtb_ext/request_wrapper.go index 7b73d31867..52ed2ba91f 100644 --- a/openrtb_ext/request_wrapper.go +++ b/openrtb_ext/request_wrapper.go @@ -7,8 +7,8 @@ import ( "slices" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) // RequestWrapper wraps the OpenRTB request to provide a storage location for unmarshalled ext fields, so they diff --git a/openrtb_ext/request_wrapper_test.go b/openrtb_ext/request_wrapper_test.go index e4c14b6031..ca332679b0 100644 --- a/openrtb_ext/request_wrapper_test.go +++ b/openrtb_ext/request_wrapper_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/site_test.go b/openrtb_ext/site_test.go index e06c0e67bd..e76e06c8c5 100644 --- a/openrtb_ext/site_test.go +++ b/openrtb_ext/site_test.go @@ -3,8 +3,8 @@ package openrtb_ext_test import ( "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/openrtb_ext/supplyChain.go b/openrtb_ext/supplyChain.go index 0051d647ff..b8abdb4c32 100644 --- a/openrtb_ext/supplyChain.go +++ b/openrtb_ext/supplyChain.go @@ -2,7 +2,7 @@ package openrtb_ext import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) func cloneSupplyChain(schain *openrtb2.SupplyChain) *openrtb2.SupplyChain { diff --git a/openrtb_ext/supplyChain_test.go b/openrtb_ext/supplyChain_test.go index 1adfaf8f62..86c2741dac 100644 --- a/openrtb_ext/supplyChain_test.go +++ b/openrtb_ext/supplyChain_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/ortb/clone.go b/ortb/clone.go index 07eaf2886b..8a0f505acd 100644 --- a/ortb/clone.go +++ b/ortb/clone.go @@ -4,7 +4,7 @@ import ( "slices" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) func CloneDataSlice(s []openrtb2.Data) []openrtb2.Data { diff --git a/ortb/clone_test.go b/ortb/clone_test.go index 14bdc0bb19..5f86b5121f 100644 --- a/ortb/clone_test.go +++ b/ortb/clone_test.go @@ -7,7 +7,7 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/ortb/default.go b/ortb/default.go index f6cc979045..43e787f39b 100644 --- a/ortb/default.go +++ b/ortb/default.go @@ -1,8 +1,8 @@ package ortb import ( - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) const ( diff --git a/ortb/default_test.go b/ortb/default_test.go index b03f546fd4..cb6af876b5 100644 --- a/ortb/default_test.go +++ b/ortb/default_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) func TestSetDefaults(t *testing.T) { diff --git a/ortb/request_validator.go b/ortb/request_validator.go index e959caa934..57ba91ff2c 100644 --- a/ortb/request_validator.go +++ b/ortb/request_validator.go @@ -4,9 +4,9 @@ import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/stored_responses" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/stored_responses" ) type ValidationConfig struct { diff --git a/ortb/request_validator_banner.go b/ortb/request_validator_banner.go index fea68121a9..c4cf9a2be0 100644 --- a/ortb/request_validator_banner.go +++ b/ortb/request_validator_banner.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func isInterstitial(imp *openrtb_ext.ImpWrapper) bool { diff --git a/ortb/request_validator_banner_test.go b/ortb/request_validator_banner_test.go index e131c32e98..a028305460 100644 --- a/ortb/request_validator_banner_test.go +++ b/ortb/request_validator_banner_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/ortb/request_validator_native.go b/ortb/request_validator_native.go index 1209a13913..7d6ff74af8 100644 --- a/ortb/request_validator_native.go +++ b/ortb/request_validator_native.go @@ -8,8 +8,8 @@ import ( "github.com/prebid/openrtb/v20/native1" nativeRequests "github.com/prebid/openrtb/v20/native1/request" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) // fillAndValidateNative validates the request, and assigns the Asset IDs as recommended by the Native v1.2 spec. diff --git a/ortb/request_validator_test.go b/ortb/request_validator_test.go index c2b6ea3c7b..4c548a7cca 100644 --- a/ortb/request_validator_test.go +++ b/ortb/request_validator_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/ortb/request_validator_video_test.go b/ortb/request_validator_video_test.go index 3d579e2c77..c8f8e4e9bc 100644 --- a/ortb/request_validator_video_test.go +++ b/ortb/request_validator_video_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/pbs/usersync.go b/pbs/usersync.go index 2a88ecc7b9..d3cc12a0aa 100644 --- a/pbs/usersync.go +++ b/pbs/usersync.go @@ -11,9 +11,9 @@ import ( "strings" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/usersync" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/usersync" ) // Recaptcha code from https://github.com/haisum/recaptcha/blob/master/recaptcha.go diff --git a/prebid_cache_client/client.go b/prebid_cache_client/client.go index adc57b97ad..07548cc53e 100644 --- a/prebid_cache_client/client.go +++ b/prebid_cache_client/client.go @@ -12,9 +12,9 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" "github.com/buger/jsonparser" "golang.org/x/net/context/ctxhttp" diff --git a/prebid_cache_client/client_test.go b/prebid_cache_client/client_test.go index 31fc05d30b..1b6e146992 100644 --- a/prebid_cache_client/client_test.go +++ b/prebid_cache_client/client_test.go @@ -10,10 +10,10 @@ import ( "strconv" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - metricsConf "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + metricsConf "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" diff --git a/privacy/activitycontrol.go b/privacy/activitycontrol.go index 674d751988..4f3d5b1a51 100644 --- a/privacy/activitycontrol.go +++ b/privacy/activitycontrol.go @@ -1,8 +1,8 @@ package privacy import ( - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) type ActivityResult int diff --git a/privacy/activitycontrol_test.go b/privacy/activitycontrol_test.go index add20ad2c3..8a8d6a03c6 100644 --- a/privacy/activitycontrol_test.go +++ b/privacy/activitycontrol_test.go @@ -3,9 +3,9 @@ package privacy import ( "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/privacy/ccpa/consentwriter_test.go b/privacy/ccpa/consentwriter_test.go index 6d0b89e24c..e087cd13ac 100644 --- a/privacy/ccpa/consentwriter_test.go +++ b/privacy/ccpa/consentwriter_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/privacy/ccpa/parsedpolicy.go b/privacy/ccpa/parsedpolicy.go index 98b04a1632..c442bd4d23 100644 --- a/privacy/ccpa/parsedpolicy.go +++ b/privacy/ccpa/parsedpolicy.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) const ( diff --git a/privacy/ccpa/policy.go b/privacy/ccpa/policy.go index b4841a174f..a32c41cc34 100644 --- a/privacy/ccpa/policy.go +++ b/privacy/ccpa/policy.go @@ -7,9 +7,9 @@ import ( gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - gppPolicy "github.com/prebid/prebid-server/v3/privacy/gpp" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + gppPolicy "github.com/prebid/prebid-server/v4/privacy/gpp" ) // Policy represents the CCPA regulatory information from an OpenRTB bid request. diff --git a/privacy/ccpa/policy_test.go b/privacy/ccpa/policy_test.go index 89bb2ccf04..5274c566f4 100644 --- a/privacy/ccpa/policy_test.go +++ b/privacy/ccpa/policy_test.go @@ -8,7 +8,7 @@ import ( gpplib "github.com/prebid/go-gpp" gppConstants "github.com/prebid/go-gpp/constants" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/privacy/lmt/ios.go b/privacy/lmt/ios.go index 7778a02d0a..ccfa409f05 100644 --- a/privacy/lmt/ios.go +++ b/privacy/lmt/ios.go @@ -4,8 +4,8 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/iosutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iosutil" ) var ( diff --git a/privacy/lmt/ios_test.go b/privacy/lmt/ios_test.go index 42636759eb..e0c98c5b61 100644 --- a/privacy/lmt/ios_test.go +++ b/privacy/lmt/ios_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/util/iosutil" + "github.com/prebid/prebid-server/v4/util/iosutil" "github.com/stretchr/testify/assert" ) diff --git a/privacy/rule_condition_test.go b/privacy/rule_condition_test.go index 97bdeef35f..aaa6ac51f4 100644 --- a/privacy/rule_condition_test.go +++ b/privacy/rule_condition_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/privacy/scrubber.go b/privacy/scrubber.go index 8f4a9b103f..fbda5b88c6 100644 --- a/privacy/scrubber.go +++ b/privacy/scrubber.go @@ -4,12 +4,12 @@ import ( "encoding/json" "net" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iputil" ) type IPConf struct { diff --git a/privacy/scrubber_test.go b/privacy/scrubber_test.go index ccb065bccb..0c8813b5d5 100644 --- a/privacy/scrubber_test.go +++ b/privacy/scrubber_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/privacysandbox/topics.go b/privacysandbox/topics.go index 3ed620b4bd..8483321315 100644 --- a/privacysandbox/topics.go +++ b/privacysandbox/topics.go @@ -8,8 +8,8 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type Topic struct { diff --git a/privacysandbox/topics_test.go b/privacysandbox/topics_test.go index 73d5ef0c12..64c1de0ec8 100644 --- a/privacysandbox/topics_test.go +++ b/privacysandbox/topics_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" "github.com/stretchr/testify/assert" ) diff --git a/router/admin.go b/router/admin.go index a90e5f233d..8751452212 100644 --- a/router/admin.go +++ b/router/admin.go @@ -5,9 +5,9 @@ import ( "net/http/pprof" "time" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/endpoints" - "github.com/prebid/prebid-server/v3/version" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/endpoints" + "github.com/prebid/prebid-server/v4/version" ) func Admin(rateConverter *currency.RateConverter, rateConverterFetchingInterval time.Duration) *http.ServeMux { diff --git a/router/aspects/request_timeout_handler.go b/router/aspects/request_timeout_handler.go index 0a4d147d90..6dee25a525 100644 --- a/router/aspects/request_timeout_handler.go +++ b/router/aspects/request_timeout_handler.go @@ -6,8 +6,8 @@ import ( "time" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" ) func QueuedRequestTimeout(f httprouter.Handle, reqTimeoutHeaders config.RequestTimeoutHeaders, metricsEngine metrics.MetricsEngine, requestType metrics.RequestType) httprouter.Handle { diff --git a/router/aspects/request_timeout_handler_test.go b/router/aspects/request_timeout_handler_test.go index 2ac8f36ae3..2cfb144802 100644 --- a/router/aspects/request_timeout_handler_test.go +++ b/router/aspects/request_timeout_handler_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" "github.com/stretchr/testify/assert" ) diff --git a/router/router.go b/router/router.go index 376b6215fe..766eadf796 100644 --- a/router/router.go +++ b/router/router.go @@ -12,36 +12,36 @@ import ( "time" openrtb2model "github.com/prebid/openrtb/v20/openrtb2" - analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/currency" - "github.com/prebid/prebid-server/v3/endpoints" - "github.com/prebid/prebid-server/v3/endpoints/events" - infoEndpoints "github.com/prebid/prebid-server/v3/endpoints/info" - "github.com/prebid/prebid-server/v3/endpoints/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/exchange" - "github.com/prebid/prebid-server/v3/experiment/adscert" - "github.com/prebid/prebid-server/v3/floors" - "github.com/prebid/prebid-server/v3/gdpr" - "github.com/prebid/prebid-server/v3/hooks" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/macros" - "github.com/prebid/prebid-server/v3/metrics" - metricsConf "github.com/prebid/prebid-server/v3/metrics/config" - "github.com/prebid/prebid-server/v3/modules" - "github.com/prebid/prebid-server/v3/modules/moduledeps" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/ortb" - "github.com/prebid/prebid-server/v3/pbs" - pbc "github.com/prebid/prebid-server/v3/prebid_cache_client" - "github.com/prebid/prebid-server/v3/router/aspects" - "github.com/prebid/prebid-server/v3/server/ssl" - storedRequestsConf "github.com/prebid/prebid-server/v3/stored_requests/config" - "github.com/prebid/prebid-server/v3/usersync" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/uuidutil" - "github.com/prebid/prebid-server/v3/version" + analyticsBuild "github.com/prebid/prebid-server/v4/analytics/build" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/currency" + "github.com/prebid/prebid-server/v4/endpoints" + "github.com/prebid/prebid-server/v4/endpoints/events" + infoEndpoints "github.com/prebid/prebid-server/v4/endpoints/info" + "github.com/prebid/prebid-server/v4/endpoints/openrtb2" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/exchange" + "github.com/prebid/prebid-server/v4/experiment/adscert" + "github.com/prebid/prebid-server/v4/floors" + "github.com/prebid/prebid-server/v4/gdpr" + "github.com/prebid/prebid-server/v4/hooks" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/macros" + "github.com/prebid/prebid-server/v4/metrics" + metricsConf "github.com/prebid/prebid-server/v4/metrics/config" + "github.com/prebid/prebid-server/v4/modules" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/ortb" + "github.com/prebid/prebid-server/v4/pbs" + pbc "github.com/prebid/prebid-server/v4/prebid_cache_client" + "github.com/prebid/prebid-server/v4/router/aspects" + "github.com/prebid/prebid-server/v4/server/ssl" + storedRequestsConf "github.com/prebid/prebid-server/v4/stored_requests/config" + "github.com/prebid/prebid-server/v4/usersync" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/uuidutil" + "github.com/prebid/prebid-server/v4/version" _ "github.com/go-sql-driver/mysql" "github.com/julienschmidt/httprouter" diff --git a/router/router_test.go b/router/router_test.go index 2566744609..6023f7ae05 100644 --- a/router/router_test.go +++ b/router/router_test.go @@ -8,9 +8,9 @@ import ( "testing" jsoniter "github.com/json-iterator/go" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/rules/schema_functions.go b/rules/schema_functions.go index 32a5c6a4b5..5ed668811c 100644 --- a/rules/schema_functions.go +++ b/rules/schema_functions.go @@ -7,10 +7,10 @@ import ( "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/randomutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/randomutil" ) const ( diff --git a/rules/schema_functions_test.go b/rules/schema_functions_test.go index 46b03dc380..033fb1ef9d 100644 --- a/rules/schema_functions_test.go +++ b/rules/schema_functions_test.go @@ -7,10 +7,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" - "github.com/prebid/prebid-server/v3/util/randomutil" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/randomutil" "github.com/stretchr/testify/assert" ) diff --git a/schain/schain.go b/schain/schain.go index cdd1e14449..e88d47c143 100644 --- a/schain/schain.go +++ b/schain/schain.go @@ -5,7 +5,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // BidderToPrebidSChains organizes the ORTB 2.5 multiple root schain nodes into a map of schain nodes by bidder diff --git a/schain/schain_test.go b/schain/schain_test.go index f112c9ec7e..040522d8ff 100644 --- a/schain/schain_test.go +++ b/schain/schain_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/schain/schainwriter.go b/schain/schainwriter.go index 37b62c993f..36a9810a1e 100644 --- a/schain/schainwriter.go +++ b/schain/schainwriter.go @@ -2,7 +2,7 @@ package schain import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // NewSChainWriter creates an ORTB 2.5 schain writer instance diff --git a/schain/schainwriter_test.go b/schain/schainwriter_test.go index 69fda95907..ef1e02e52a 100644 --- a/schain/schainwriter_test.go +++ b/schain/schainwriter_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" diff --git a/server/listener.go b/server/listener.go index ece1a6ec3d..3bdeb176fe 100644 --- a/server/listener.go +++ b/server/listener.go @@ -5,8 +5,8 @@ import ( "strings" "time" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" ) // monitorableListener tracks any opened connections in the metrics. diff --git a/server/listener_test.go b/server/listener_test.go index 293890a1e1..b54ae35ded 100644 --- a/server/listener_test.go +++ b/server/listener_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" gometrics "github.com/rcrowley/go-metrics" ) diff --git a/server/prometheus.go b/server/prometheus.go index 332eebdd1c..2ddcc55a70 100644 --- a/server/prometheus.go +++ b/server/prometheus.go @@ -5,9 +5,9 @@ import ( "net/http" "strconv" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - metricsconfig "github.com/prebid/prebid-server/v3/metrics/config" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + metricsconfig "github.com/prebid/prebid-server/v4/metrics/config" "github.com/prometheus/client_golang/prometheus/promhttp" ) diff --git a/server/server.go b/server/server.go index f46fdc8cfe..cb3cdaf7d4 100644 --- a/server/server.go +++ b/server/server.go @@ -12,10 +12,10 @@ import ( "time" "github.com/NYTimes/gziphandler" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - metricsconfig "github.com/prebid/prebid-server/v3/metrics/config" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + metricsconfig "github.com/prebid/prebid-server/v4/metrics/config" ) // Listen blocks forever, serving PBS requests on the given port. This will block forever, until the process is shut down. diff --git a/server/server_test.go b/server/server_test.go index 6d2a3335e3..389b9884dd 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - metricsconfig "github.com/prebid/prebid-server/v3/metrics/config" + "github.com/prebid/prebid-server/v4/config" + metricsconfig "github.com/prebid/prebid-server/v4/metrics/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/stored_requests/backends/db_fetcher/fetcher.go b/stored_requests/backends/db_fetcher/fetcher.go index fc16ca490b..13c5cb00b9 100644 --- a/stored_requests/backends/db_fetcher/fetcher.go +++ b/stored_requests/backends/db_fetcher/fetcher.go @@ -5,9 +5,9 @@ import ( "encoding/json" "github.com/lib/pq" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" ) func NewFetcher( diff --git a/stored_requests/backends/db_fetcher/fetcher_test.go b/stored_requests/backends/db_fetcher/fetcher_test.go index 6da09abf7b..1f4464bcb8 100644 --- a/stored_requests/backends/db_fetcher/fetcher_test.go +++ b/stored_requests/backends/db_fetcher/fetcher_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/backends/db_provider/db_provider.go b/stored_requests/backends/db_provider/db_provider.go index be460bc351..cffdee24d9 100644 --- a/stored_requests/backends/db_provider/db_provider.go +++ b/stored_requests/backends/db_provider/db_provider.go @@ -4,8 +4,8 @@ import ( "context" "database/sql" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" ) type DbProvider interface { diff --git a/stored_requests/backends/db_provider/db_provider_mock.go b/stored_requests/backends/db_provider/db_provider_mock.go index 1b1c1ff601..37dd33f362 100644 --- a/stored_requests/backends/db_provider/db_provider_mock.go +++ b/stored_requests/backends/db_provider/db_provider_mock.go @@ -6,7 +6,7 @@ import ( "reflect" "github.com/DATA-DOG/go-sqlmock" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) func NewDbProviderMock() (*DbProviderMock, sqlmock.Sqlmock, error) { diff --git a/stored_requests/backends/db_provider/mysql_dbprovider.go b/stored_requests/backends/db_provider/mysql_dbprovider.go index bdcfacbae8..5071156f2f 100644 --- a/stored_requests/backends/db_provider/mysql_dbprovider.go +++ b/stored_requests/backends/db_provider/mysql_dbprovider.go @@ -15,7 +15,7 @@ import ( "strings" "github.com/go-sql-driver/mysql" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) const customTLSKey = "prebid-tls" diff --git a/stored_requests/backends/db_provider/mysql_dbprovider_test.go b/stored_requests/backends/db_provider/mysql_dbprovider_test.go index c12d7f5abc..474c36e4ef 100644 --- a/stored_requests/backends/db_provider/mysql_dbprovider_test.go +++ b/stored_requests/backends/db_provider/mysql_dbprovider_test.go @@ -6,7 +6,7 @@ import ( "runtime" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/backends/db_provider/postgres_dbprovider.go b/stored_requests/backends/db_provider/postgres_dbprovider.go index c94632a0f3..e58b336e48 100644 --- a/stored_requests/backends/db_provider/postgres_dbprovider.go +++ b/stored_requests/backends/db_provider/postgres_dbprovider.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) type PostgresDbProvider struct { diff --git a/stored_requests/backends/db_provider/postgres_dbprovider_test.go b/stored_requests/backends/db_provider/postgres_dbprovider_test.go index 1be77d0d28..8fed6b87a3 100644 --- a/stored_requests/backends/db_provider/postgres_dbprovider_test.go +++ b/stored_requests/backends/db_provider/postgres_dbprovider_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/backends/empty_fetcher/fetcher.go b/stored_requests/backends/empty_fetcher/fetcher.go index 405903e533..79de895ab6 100644 --- a/stored_requests/backends/empty_fetcher/fetcher.go +++ b/stored_requests/backends/empty_fetcher/fetcher.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests" ) // EmptyFetcher is a nil-object which has no Stored Requests. diff --git a/stored_requests/backends/file_fetcher/fetcher.go b/stored_requests/backends/file_fetcher/fetcher.go index 6bb8bc1447..615135f2db 100644 --- a/stored_requests/backends/file_fetcher/fetcher.go +++ b/stored_requests/backends/file_fetcher/fetcher.go @@ -8,8 +8,8 @@ import ( "os" "strings" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/jsonutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/stored_requests/backends/file_fetcher/fetcher_test.go b/stored_requests/backends/file_fetcher/fetcher_test.go index 735045dd9f..8ca38aa873 100644 --- a/stored_requests/backends/file_fetcher/fetcher_test.go +++ b/stored_requests/backends/file_fetcher/fetcher_test.go @@ -6,8 +6,8 @@ import ( "fmt" "testing" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go index 1950f2c3ee..a0e6daba5a 100644 --- a/stored_requests/backends/http_fetcher/fetcher.go +++ b/stored_requests/backends/http_fetcher/fetcher.go @@ -9,9 +9,9 @@ import ( "net/url" "strings" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/util/jsonutil" "golang.org/x/net/context/ctxhttp" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) diff --git a/stored_requests/backends/http_fetcher/fetcher_test.go b/stored_requests/backends/http_fetcher/fetcher_test.go index 6dfa12b250..e98032480c 100644 --- a/stored_requests/backends/http_fetcher/fetcher_test.go +++ b/stored_requests/backends/http_fetcher/fetcher_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/caches/cachestest/reliable.go b/stored_requests/caches/cachestest/reliable.go index f4042e28c4..abea2dbff8 100644 --- a/stored_requests/caches/cachestest/reliable.go +++ b/stored_requests/caches/cachestest/reliable.go @@ -5,7 +5,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests" ) const ( diff --git a/stored_requests/caches/memory/cache.go b/stored_requests/caches/memory/cache.go index bae7a7ddcf..42d26e3e8e 100644 --- a/stored_requests/caches/memory/cache.go +++ b/stored_requests/caches/memory/cache.go @@ -6,8 +6,8 @@ import ( "sync" "github.com/coocood/freecache" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/stored_requests" ) // NewCache returns an in-memory Cache which evicts items if: diff --git a/stored_requests/caches/memory/cache_test.go b/stored_requests/caches/memory/cache_test.go index 91548e4693..26eab878e1 100644 --- a/stored_requests/caches/memory/cache_test.go +++ b/stored_requests/caches/memory/cache_test.go @@ -7,8 +7,8 @@ import ( "strconv" "testing" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/caches/cachestest" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/caches/cachestest" ) func TestLRURobustness(t *testing.T) { diff --git a/stored_requests/caches/memory/maps.go b/stored_requests/caches/memory/maps.go index adf5b2a90d..501dc5ccbe 100644 --- a/stored_requests/caches/memory/maps.go +++ b/stored_requests/caches/memory/maps.go @@ -5,7 +5,7 @@ import ( "sync" "github.com/coocood/freecache" - "github.com/prebid/prebid-server/v3/logger" + "github.com/prebid/prebid-server/v4/logger" ) // This file contains an interface and some wrapper types for various types of "map-like" structures diff --git a/stored_requests/config/config.go b/stored_requests/config/config.go index 5ff729cdd3..87802589eb 100644 --- a/stored_requests/config/config.go +++ b/stored_requests/config/config.go @@ -6,22 +6,22 @@ import ( "time" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/backends/file_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/backends/http_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/caches/memory" - "github.com/prebid/prebid-server/v3/stored_requests/caches/nil_cache" - "github.com/prebid/prebid-server/v3/stored_requests/events" - apiEvents "github.com/prebid/prebid-server/v3/stored_requests/events/api" - databaseEvents "github.com/prebid/prebid-server/v3/stored_requests/events/database" - httpEvents "github.com/prebid/prebid-server/v3/stored_requests/events/http" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/backends/file_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/backends/http_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/caches/memory" + "github.com/prebid/prebid-server/v4/stored_requests/caches/nil_cache" + "github.com/prebid/prebid-server/v4/stored_requests/events" + apiEvents "github.com/prebid/prebid-server/v4/stored_requests/events/api" + databaseEvents "github.com/prebid/prebid-server/v4/stored_requests/events/database" + httpEvents "github.com/prebid/prebid-server/v4/stored_requests/events/http" + "github.com/prebid/prebid-server/v4/util/task" ) // CreateStoredRequests returns three things: diff --git a/stored_requests/config/config_test.go b/stored_requests/config/config_test.go index 87b396c926..913f8c3959 100644 --- a/stored_requests/config/config_test.go +++ b/stored_requests/config/config_test.go @@ -13,14 +13,14 @@ import ( sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" - "github.com/prebid/prebid-server/v3/stored_requests/backends/empty_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/backends/http_fetcher" - "github.com/prebid/prebid-server/v3/stored_requests/events" - httpEvents "github.com/prebid/prebid-server/v3/stored_requests/events/http" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/stored_requests/backends/empty_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/backends/http_fetcher" + "github.com/prebid/prebid-server/v4/stored_requests/events" + httpEvents "github.com/prebid/prebid-server/v4/stored_requests/events/http" "github.com/stretchr/testify/mock" ) diff --git a/stored_requests/events/api/api.go b/stored_requests/events/api/api.go index c9f87e0ae7..652399717e 100644 --- a/stored_requests/events/api/api.go +++ b/stored_requests/events/api/api.go @@ -5,8 +5,8 @@ import ( "net/http" "github.com/julienschmidt/httprouter" - "github.com/prebid/prebid-server/v3/stored_requests/events" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/stored_requests/events" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type eventsAPI struct { diff --git a/stored_requests/events/api/api_test.go b/stored_requests/events/api/api_test.go index c5d67a9b86..87a516f792 100644 --- a/stored_requests/events/api/api_test.go +++ b/stored_requests/events/api/api_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/caches/memory" - "github.com/prebid/prebid-server/v3/stored_requests/events" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/caches/memory" + "github.com/prebid/prebid-server/v4/stored_requests/events" ) func TestGoodRequests(t *testing.T) { diff --git a/stored_requests/events/database/database.go b/stored_requests/events/database/database.go index 1ab768c97c..c29bc4a855 100644 --- a/stored_requests/events/database/database.go +++ b/stored_requests/events/database/database.go @@ -8,12 +8,12 @@ import ( "net" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" - "github.com/prebid/prebid-server/v3/stored_requests/events" - "github.com/prebid/prebid-server/v3/util/timeutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/stored_requests/events" + "github.com/prebid/prebid-server/v4/util/timeutil" ) func bytesNull() []byte { diff --git a/stored_requests/events/database/database_test.go b/stored_requests/events/database/database_test.go index ffe02851ca..0c09f376dd 100644 --- a/stored_requests/events/database/database_test.go +++ b/stored_requests/events/database/database_test.go @@ -7,10 +7,10 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests/backends/db_provider" - "github.com/prebid/prebid-server/v3/stored_requests/events" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests/backends/db_provider" + "github.com/prebid/prebid-server/v4/stored_requests/events" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" diff --git a/stored_requests/events/events.go b/stored_requests/events/events.go index e96692826b..f0d30878c9 100644 --- a/stored_requests/events/events.go +++ b/stored_requests/events/events.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests" ) // Save represents a bulk save diff --git a/stored_requests/events/events_test.go b/stored_requests/events/events_test.go index 4520a33255..9f977c8e9f 100644 --- a/stored_requests/events/events_test.go +++ b/stored_requests/events/events_test.go @@ -7,8 +7,8 @@ import ( "reflect" "testing" - "github.com/prebid/prebid-server/v3/stored_requests" - "github.com/prebid/prebid-server/v3/stored_requests/caches/memory" + "github.com/prebid/prebid-server/v4/stored_requests" + "github.com/prebid/prebid-server/v4/stored_requests/caches/memory" ) func TestListen(t *testing.T) { diff --git a/stored_requests/events/http/http.go b/stored_requests/events/http/http.go index f987afb658..2765cb4aae 100644 --- a/stored_requests/events/http/http.go +++ b/stored_requests/events/http/http.go @@ -10,9 +10,9 @@ import ( "time" "github.com/buger/jsonparser" - "github.com/prebid/prebid-server/v3/logger" - "github.com/prebid/prebid-server/v3/stored_requests/events" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/logger" + "github.com/prebid/prebid-server/v4/stored_requests/events" + "github.com/prebid/prebid-server/v4/util/jsonutil" "golang.org/x/net/context/ctxhttp" ) diff --git a/stored_requests/events/http/http_test.go b/stored_requests/events/http/http_test.go index 90fd61371c..9254484688 100644 --- a/stored_requests/events/http/http_test.go +++ b/stored_requests/events/http/http_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" "github.com/stretchr/testify/assert" ) diff --git a/stored_requests/fetcher.go b/stored_requests/fetcher.go index 343e1f82d5..2abfb33052 100644 --- a/stored_requests/fetcher.go +++ b/stored_requests/fetcher.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/metrics" + "github.com/prebid/prebid-server/v4/metrics" ) // Fetcher knows how to fetch Stored Request data by id. diff --git a/stored_requests/fetcher_test.go b/stored_requests/fetcher_test.go index c97340cbdb..4481600e9d 100644 --- a/stored_requests/fetcher_test.go +++ b/stored_requests/fetcher_test.go @@ -6,8 +6,8 @@ import ( "errors" "testing" - "github.com/prebid/prebid-server/v3/metrics" - "github.com/prebid/prebid-server/v3/stored_requests/caches/nil_cache" + "github.com/prebid/prebid-server/v4/metrics" + "github.com/prebid/prebid-server/v4/stored_requests/caches/nil_cache" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" diff --git a/stored_responses/stored_responses.go b/stored_responses/stored_responses.go index 6c8d4ae5f6..a7a3abc4f3 100644 --- a/stored_responses/stored_responses.go +++ b/stored_responses/stored_responses.go @@ -7,8 +7,8 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/stored_requests" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/stored_requests" ) type ImpsWithAuctionResponseIDs map[string]string diff --git a/stored_responses/stored_responses_test.go b/stored_responses/stored_responses_test.go index 0dcd5e9a6d..09bf429a9f 100644 --- a/stored_responses/stored_responses_test.go +++ b/stored_responses/stored_responses_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/usersync/chooser.go b/usersync/chooser.go index 31a14a4d43..bc2d0812a7 100644 --- a/usersync/chooser.go +++ b/usersync/chooser.go @@ -3,8 +3,8 @@ package usersync import ( "strings" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) // Chooser determines which syncers are eligible for a given request. diff --git a/usersync/chooser_test.go b/usersync/chooser_test.go index 2674330c30..569dd0ea11 100644 --- a/usersync/chooser_test.go +++ b/usersync/chooser_test.go @@ -4,13 +4,13 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/prebid/prebid-server/v3/macros" + "github.com/prebid/prebid-server/v4/macros" ) func TestNewChooser(t *testing.T) { diff --git a/usersync/cookie.go b/usersync/cookie.go index dce5b02095..410bece531 100644 --- a/usersync/cookie.go +++ b/usersync/cookie.go @@ -5,9 +5,9 @@ import ( "net/http" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) const uidCookieName = "uids" diff --git a/usersync/cookie_test.go b/usersync/cookie_test.go index 79193d92a6..6b803591f6 100644 --- a/usersync/cookie_test.go +++ b/usersync/cookie_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" ) diff --git a/usersync/decoder.go b/usersync/decoder.go index d77c8d426b..30a0c5ceb6 100644 --- a/usersync/decoder.go +++ b/usersync/decoder.go @@ -3,7 +3,7 @@ package usersync import ( "encoding/base64" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type Decoder interface { diff --git a/usersync/encoder.go b/usersync/encoder.go index 6a7db1fe51..14c71ed3b4 100644 --- a/usersync/encoder.go +++ b/usersync/encoder.go @@ -3,7 +3,7 @@ package usersync import ( "encoding/base64" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type Encoder interface { diff --git a/usersync/syncer.go b/usersync/syncer.go index b96b79cce2..10ec089abb 100644 --- a/usersync/syncer.go +++ b/usersync/syncer.go @@ -9,8 +9,8 @@ import ( "text/template" validator "github.com/asaskevich/govalidator" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/macros" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/macros" ) var ( diff --git a/usersync/syncer_test.go b/usersync/syncer_test.go index 1670a3452e..827dee4628 100644 --- a/usersync/syncer_test.go +++ b/usersync/syncer_test.go @@ -4,8 +4,8 @@ import ( "testing" "text/template" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/macros" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/macros" "github.com/stretchr/testify/assert" ) diff --git a/usersync/syncersbuilder.go b/usersync/syncersbuilder.go index 2868a1da7d..b8a11e66dd 100644 --- a/usersync/syncersbuilder.go +++ b/usersync/syncersbuilder.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v4/config" ) type namedSyncerConfig struct { diff --git a/usersync/syncersbuilder_test.go b/usersync/syncersbuilder_test.go index f86808a21f..b32b741b7c 100644 --- a/usersync/syncersbuilder_test.go +++ b/usersync/syncersbuilder_test.go @@ -4,8 +4,8 @@ import ( "errors" "testing" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/macros" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/macros" "github.com/stretchr/testify/assert" ) diff --git a/util/httputil/httputil.go b/util/httputil/httputil.go index dd09cdadf4..3cf80b8c77 100644 --- a/util/httputil/httputil.go +++ b/util/httputil/httputil.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/util/iputil" ) var ( diff --git a/util/httputil/httputil_test.go b/util/httputil/httputil_test.go index 2b2f52e5c5..f8b9ba5440 100644 --- a/util/httputil/httputil_test.go +++ b/util/httputil/httputil_test.go @@ -5,7 +5,7 @@ import ( "net/http" "testing" - "github.com/prebid/prebid-server/v3/util/iputil" + "github.com/prebid/prebid-server/v4/util/iputil" "github.com/stretchr/testify/assert" ) diff --git a/util/jsonutil/forcestring.go b/util/jsonutil/forcestring.go index 64ce2a6795..e16d85683d 100644 --- a/util/jsonutil/forcestring.go +++ b/util/jsonutil/forcestring.go @@ -3,7 +3,7 @@ package jsonutil import ( "errors" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/tidwall/gjson" ) diff --git a/util/jsonutil/forcestring_test.go b/util/jsonutil/forcestring_test.go index 60f87fafa4..3fc1cb6803 100644 --- a/util/jsonutil/forcestring_test.go +++ b/util/jsonutil/forcestring_test.go @@ -3,7 +3,7 @@ package jsonutil import ( "testing" - "github.com/prebid/prebid-server/v3/util/ptrutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" "github.com/stretchr/testify/assert" ) diff --git a/util/jsonutil/jsonutil.go b/util/jsonutil/jsonutil.go index 2598044ff7..da9027c1df 100644 --- a/util/jsonutil/jsonutil.go +++ b/util/jsonutil/jsonutil.go @@ -9,7 +9,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/modern-go/reflect2" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) const ( diff --git a/util/jsonutil/merge.go b/util/jsonutil/merge.go index 6dff8afca6..9e530a5464 100644 --- a/util/jsonutil/merge.go +++ b/util/jsonutil/merge.go @@ -10,7 +10,7 @@ import ( "github.com/modern-go/reflect2" jsonpatch "gopkg.in/evanphx/json-patch.v5" - "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v4/errortypes" ) // jsonConfigMergeClone uses the same configuration as the `ConfigCompatibleWithStandardLibrary` profile diff --git a/util/task/ticker_task_test.go b/util/task/ticker_task_test.go index b1acb35ffa..774febd6c8 100644 --- a/util/task/ticker_task_test.go +++ b/util/task/ticker_task_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/prebid/prebid-server/v3/util/task" + "github.com/prebid/prebid-server/v4/util/task" "github.com/stretchr/testify/assert" ) diff --git a/version/xprebidheader.go b/version/xprebidheader.go index 7e31aa4b11..056246474c 100644 --- a/version/xprebidheader.go +++ b/version/xprebidheader.go @@ -5,7 +5,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) const xPrebidHeaderVersionPrefix = "pbs-go" diff --git a/version/xprebidheader_test.go b/version/xprebidheader_test.go index 15a73fe98f..0e74584c7e 100644 --- a/version/xprebidheader_test.go +++ b/version/xprebidheader_test.go @@ -6,8 +6,8 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) func TestBuildXPrebidHeader(t *testing.T) { From 5d6c775cb34455536196b8efe12457221feb6298 Mon Sep 17 00:00:00 2001 From: nuba-io <github@nuba.io> Date: Fri, 20 Mar 2026 20:42:30 +0200 Subject: [PATCH 186/272] New Adapter: Nuba (#4565) --- static/bidder-info/nuba.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/nuba.yaml diff --git a/static/bidder-info/nuba.yaml b/static/bidder-info/nuba.yaml new file mode 100644 index 0000000000..803402c68a --- /dev/null +++ b/static/bidder-info/nuba.yaml @@ -0,0 +1,4 @@ +aliasOf: "teqblaze" +endpoint: "https://ads.nuba.io/pserver" +maintainer: + email: "tech@nuba.io" From 99009c08fb6204ec10f236653a7fc47c229339c3 Mon Sep 17 00:00:00 2001 From: Parth Shah <parth@deepintent.com> Date: Wed, 25 Mar 2026 22:56:52 +0530 Subject: [PATCH 187/272] adds geoscope for deepintent (#4721) --- static/bidder-info/deepintent.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/static/bidder-info/deepintent.yaml b/static/bidder-info/deepintent.yaml index 95aba4207a..c19b29f90d 100644 --- a/static/bidder-info/deepintent.yaml +++ b/static/bidder-info/deepintent.yaml @@ -1,4 +1,6 @@ endpoint: "https://prebid.deepintent.com/prebid" +geoscope: + - USA maintainer: email: "prebiddev@deepintent.com" gvlVendorID: 541 From 33c0e5eb2251ba2b1964f157404ee417516804f7 Mon Sep 17 00:00:00 2001 From: driftpixelai <166716541+driftpixelai@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:18:46 +0300 Subject: [PATCH 188/272] New Adapter: DPAI (#4684) --- static/bidder-info/dpai.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 static/bidder-info/dpai.yaml diff --git a/static/bidder-info/dpai.yaml b/static/bidder-info/dpai.yaml new file mode 100644 index 0000000000..f679d66d77 --- /dev/null +++ b/static/bidder-info/dpai.yaml @@ -0,0 +1,22 @@ +aliasOf: "teqblaze" +endpoint: "https://ssp.drift-pixel.ai/pserver" +maintainer: + email: "adops@driftpixel.ai" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://sync.drift-pixel.ai/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://sync.drift-pixel.ai/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 51756a8e1132802fd89319e8e3cbde37b27739e5 Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:07:45 +0300 Subject: [PATCH 189/272] New Adapter: Amcom - Attekmi alias (#4617) --- static/bidder-info/amcom.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/amcom.yaml diff --git a/static/bidder-info/amcom.yaml b/static/bidder-info/amcom.yaml new file mode 100644 index 0000000000..2144fe6b2e --- /dev/null +++ b/static/bidder-info/amcom.yaml @@ -0,0 +1,2 @@ +endpoint: "https://amcom-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +aliasOf: "smarthub" From 3061e44e28a078e2cfd73323450da78ce4c263d0 Mon Sep 17 00:00:00 2001 From: Anna Yablonsky <annay@perion.com> Date: Fri, 3 Apr 2026 21:17:44 +0300 Subject: [PATCH 190/272] New Adapter: Adnimation - Vidazoo Alias (#4695) Co-authored-by: Anna Yablonsky <annay+perion@perion.com> --- static/bidder-info/adnimation.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/bidder-info/adnimation.yaml diff --git a/static/bidder-info/adnimation.yaml b/static/bidder-info/adnimation.yaml new file mode 100644 index 0000000000..308c048314 --- /dev/null +++ b/static/bidder-info/adnimation.yaml @@ -0,0 +1,8 @@ +aliasOf: "vidazoo" +endpoint: "https://exchange.adnimation.com/openrtb/" +maintainer: + email: "prebid@adnimation.com" +userSync: + iframe: + url: https://sync.adnimation.com/api/user/html/697a076271875e8907df35a6?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} From 86cff4b102992e1b9787d20af1d467502f1a4ed8 Mon Sep 17 00:00:00 2001 From: verben-gh <ezequiel.espino@verben.com> Date: Fri, 3 Apr 2026 21:26:32 +0300 Subject: [PATCH 191/272] New Adapter: Verben (#4693) --- static/bidder-info/verben.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/verben.yaml diff --git a/static/bidder-info/verben.yaml b/static/bidder-info/verben.yaml new file mode 100644 index 0000000000..a5b9cfed3d --- /dev/null +++ b/static/bidder-info/verben.yaml @@ -0,0 +1,4 @@ +aliasOf: "teqblaze" +endpoint: "https://east-node.verben.com/pserver" +maintainer: + email: "support_trading@verben.com" From 69de874dc498ce07013f6eda2a1e01361a0d7db6 Mon Sep 17 00:00:00 2001 From: johnwier <49074029+johnwier@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:42:14 -0700 Subject: [PATCH 192/272] Conversant: Pass prebid version number through (#4688) Co-authored-by: johwier <john.wier@epsilon.com> --- adapters/conversant/conversant.go | 6 +++++- adapters/conversant/conversanttest/exemplary/banner.json | 1 - .../conversant/conversanttest/exemplary/simple-native.json | 3 +-- .../conversant/conversanttest/exemplary/simple_app.json | 1 - .../conversanttest/exemplary/simple_audio_app.json | 1 - .../conversanttest/exemplary/simple_audio_site.json | 1 - adapters/conversant/conversanttest/exemplary/video.json | 1 - .../conversanttest/supplemental/server_badresponse.json | 1 - .../conversanttest/supplemental/server_nocontent.json | 1 - .../conversanttest/supplemental/server_unknownstatus.json | 1 - .../conversant/conversanttest/supplemental/test_params.json | 4 ---- 11 files changed, 6 insertions(+), 15 deletions(-) diff --git a/adapters/conversant/conversant.go b/adapters/conversant/conversant.go index 67056dc569..66ae47412a 100644 --- a/adapters/conversant/conversant.go +++ b/adapters/conversant/conversant.go @@ -3,6 +3,7 @@ package conversant import ( "encoding/json" "fmt" + "github.com/prebid/prebid-server/v3/version" "net/http" "strings" @@ -84,7 +85,10 @@ func (c *ConversantAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo * func parseCnvrParams(imp *openrtb2.Imp, cnvrExt openrtb_ext.ExtImpConversant, reqInfo *adapters.ExtraRequestInfo) []error { imp.DisplayManager = "prebid-s2s" - imp.DisplayManagerVer = "2.0.0" + + if version.Ver != "" { + imp.DisplayManagerVer = version.Ver + } if imp.BidFloor <= 0 && cnvrExt.BidFloor > 0 { imp.BidFloor = cnvrExt.BidFloor diff --git a/adapters/conversant/conversanttest/exemplary/banner.json b/adapters/conversant/conversanttest/exemplary/banner.json index 8523bb671d..c84c9405db 100644 --- a/adapters/conversant/conversanttest/exemplary/banner.json +++ b/adapters/conversant/conversanttest/exemplary/banner.json @@ -42,7 +42,6 @@ "secure": 1, "bidfloor": 0.01, "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "banner": { "format": [{"w": 300, "h": 250}] }, diff --git a/adapters/conversant/conversanttest/exemplary/simple-native.json b/adapters/conversant/conversanttest/exemplary/simple-native.json index f1c67e548a..e32dad2f08 100644 --- a/adapters/conversant/conversanttest/exemplary/simple-native.json +++ b/adapters/conversant/conversanttest/exemplary/simple-native.json @@ -35,7 +35,6 @@ "secure": 1, "bidfloor": 0.01, "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "ext": { "bidder": { "site_id": "108060", @@ -97,4 +96,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/conversant/conversanttest/exemplary/simple_app.json b/adapters/conversant/conversanttest/exemplary/simple_app.json index a4c825e1f6..e3ef3db1c2 100644 --- a/adapters/conversant/conversanttest/exemplary/simple_app.json +++ b/adapters/conversant/conversanttest/exemplary/simple_app.json @@ -46,7 +46,6 @@ "secure": 1, "bidfloor": 0.01, "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "banner": { "format": [{"w": 300, "h": 250}] }, diff --git a/adapters/conversant/conversanttest/exemplary/simple_audio_app.json b/adapters/conversant/conversanttest/exemplary/simple_audio_app.json index fd0b091085..64ae162520 100644 --- a/adapters/conversant/conversanttest/exemplary/simple_audio_app.json +++ b/adapters/conversant/conversanttest/exemplary/simple_audio_app.json @@ -42,7 +42,6 @@ "secure": 1, "bidfloor": 0.01, "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "audio": { "mimes": [ "audio/vnd.wav", "audio/mpeg", "audio/mp4" ], "protocols": [3,6,7,8] diff --git a/adapters/conversant/conversanttest/exemplary/simple_audio_site.json b/adapters/conversant/conversanttest/exemplary/simple_audio_site.json index fb74e0b673..d2b4f849c3 100644 --- a/adapters/conversant/conversanttest/exemplary/simple_audio_site.json +++ b/adapters/conversant/conversanttest/exemplary/simple_audio_site.json @@ -44,7 +44,6 @@ "secure": 1, "bidfloor": 0.01, "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "audio": { "mimes": [ "audio/vnd.wav", "audio/mpeg", "audio/mp4" ], "protocols": [3,6,7,8] diff --git a/adapters/conversant/conversanttest/exemplary/video.json b/adapters/conversant/conversanttest/exemplary/video.json index 322e28ad51..023b159cd9 100644 --- a/adapters/conversant/conversanttest/exemplary/video.json +++ b/adapters/conversant/conversanttest/exemplary/video.json @@ -63,7 +63,6 @@ "bidfloor": 25.0, "bidfloorcur": "USD", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "video": { "w": 300, "h": 250, diff --git a/adapters/conversant/conversanttest/supplemental/server_badresponse.json b/adapters/conversant/conversanttest/supplemental/server_badresponse.json index 26c74eaa66..60e9b78bf3 100644 --- a/adapters/conversant/conversanttest/supplemental/server_badresponse.json +++ b/adapters/conversant/conversanttest/supplemental/server_badresponse.json @@ -31,7 +31,6 @@ { "id": "1", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "banner": { "format": [{"w": 300, "h": 250}] }, diff --git a/adapters/conversant/conversanttest/supplemental/server_nocontent.json b/adapters/conversant/conversanttest/supplemental/server_nocontent.json index ca33f470a5..4faff08b96 100644 --- a/adapters/conversant/conversanttest/supplemental/server_nocontent.json +++ b/adapters/conversant/conversanttest/supplemental/server_nocontent.json @@ -31,7 +31,6 @@ { "id": "1", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "banner": { "format": [{"w": 300, "h": 250}] }, diff --git a/adapters/conversant/conversanttest/supplemental/server_unknownstatus.json b/adapters/conversant/conversanttest/supplemental/server_unknownstatus.json index 129b6fba02..acb9741435 100644 --- a/adapters/conversant/conversanttest/supplemental/server_unknownstatus.json +++ b/adapters/conversant/conversanttest/supplemental/server_unknownstatus.json @@ -31,7 +31,6 @@ { "id": "1", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "banner": { "format": [{"w": 300, "h": 250}] }, diff --git a/adapters/conversant/conversanttest/supplemental/test_params.json b/adapters/conversant/conversanttest/supplemental/test_params.json index 41366dbe19..ce3efc35d0 100644 --- a/adapters/conversant/conversanttest/supplemental/test_params.json +++ b/adapters/conversant/conversanttest/supplemental/test_params.json @@ -108,7 +108,6 @@ "secure": 1, "tagid": "mytag", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "video": { "api": [1,2], "maxduration": 60, @@ -127,7 +126,6 @@ "secure": 1, "tagid": "mytag", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "video": { "api": [1,2], "maxduration": 60, @@ -155,7 +153,6 @@ "secure": 1, "tagid": "mytag", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "video": { "api": [1,2], "maxduration": 60, @@ -183,7 +180,6 @@ "secure": 1, "tagid": "mytag", "displaymanager": "prebid-s2s", - "displaymanagerver": "2.0.0", "video": { "api": [1,2], "maxduration": 60, From ab8961e899d55a1c2fc9c397acc0deb18690d3dd Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:19:20 -0400 Subject: [PATCH 193/272] Conversant: Fix version package reference (#4739) --- adapters/conversant/conversant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/conversant/conversant.go b/adapters/conversant/conversant.go index 66ae47412a..f5db218286 100644 --- a/adapters/conversant/conversant.go +++ b/adapters/conversant/conversant.go @@ -3,7 +3,6 @@ package conversant import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/v3/version" "net/http" "strings" @@ -14,6 +13,7 @@ import ( "github.com/prebid/prebid-server/v4/errortypes" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/version" ) type ConversantAdapter struct { From 3c215fbea0ab8d84fead940af5615dd0945518f2 Mon Sep 17 00:00:00 2001 From: Anna Yablonsky <annay@perion.com> Date: Sat, 4 Apr 2026 18:19:00 +0300 Subject: [PATCH 194/272] New Adapter: Apester (#4698) Co-authored-by: Anna Yablonsky <annay+perion@perion.com> --- static/bidder-info/apester.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/apester.yaml diff --git a/static/bidder-info/apester.yaml b/static/bidder-info/apester.yaml new file mode 100644 index 0000000000..c5bd2facd0 --- /dev/null +++ b/static/bidder-info/apester.yaml @@ -0,0 +1,9 @@ +aliasOf: "vidazoo" +endpoint: "https://bidder.apester.com/openrtb/" +maintainer: + email: "info@apester.com" +userSync: + iframe: + url: https://sync.apester.com/api/user/html/699dad2322a7fa644e1d8bf7?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} +gvlVendorID: 354 \ No newline at end of file From 8fdb72f6d0b3049529c1dd94ce4054792d36c678 Mon Sep 17 00:00:00 2001 From: markappmedia <markappmedia@gmail.com> Date: Sat, 4 Apr 2026 18:36:52 +0300 Subject: [PATCH 195/272] New Adapter: Harion (#4671) --- static/bidder-info/harion.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 static/bidder-info/harion.yaml diff --git a/static/bidder-info/harion.yaml b/static/bidder-info/harion.yaml new file mode 100644 index 0000000000..450afd8644 --- /dev/null +++ b/static/bidder-info/harion.yaml @@ -0,0 +1,17 @@ +aliasOf: "teqblaze" +endpoint: "https://usads.harion-ma.com/pserver" +maintainer: + email: "adtech@markappmedia.site" +gvlVendorID: 1406 +capabilities: + site: + mediaTypes: + - banner + - video + - native + + app: + mediaTypes: + - banner + - video + - native From 5744c6a086d9f76ea6b3c9029ef014963b080cfd Mon Sep 17 00:00:00 2001 From: dev-adverxo <developer@adverxo.com> Date: Sat, 4 Apr 2026 17:45:51 +0200 Subject: [PATCH 196/272] New Adapter: Harrenmedia - Adverxo Alias (#4597) --- static/bidder-info/harrenmedia.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/harrenmedia.yaml diff --git a/static/bidder-info/harrenmedia.yaml b/static/bidder-info/harrenmedia.yaml new file mode 100644 index 0000000000..aaafa8d446 --- /dev/null +++ b/static/bidder-info/harrenmedia.yaml @@ -0,0 +1,9 @@ +endpoint: "https://harrenmedia.pbsadverxo.com/auction?id={{.AdUnit}}&auth={{.TokenID}}" +aliasOf: "adverxo" +userSync: + iframe: + url: https://hmidssp.com/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://hmidssp.com/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID From 5f775386fb53bfc25e3da421e6c5938101559a4e Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:03:05 +0300 Subject: [PATCH 197/272] New Adapter: MyCodeMedia (#4630) --- static/bidder-info/mycodemedia.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 static/bidder-info/mycodemedia.yaml diff --git a/static/bidder-info/mycodemedia.yaml b/static/bidder-info/mycodemedia.yaml new file mode 100644 index 0000000000..88b0547773 --- /dev/null +++ b/static/bidder-info/mycodemedia.yaml @@ -0,0 +1,22 @@ +aliasOf: "teqblaze" +endpoint: 'https://east-backend.mycodemedia.com/pserver' +maintainer: + email: 'support-platform@mycodemedia.com' +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://usersync.mycodemedia.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://usersync.mycodemedia.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 9178b98fb527de98b8406b0304ae2cc76ba04ccf Mon Sep 17 00:00:00 2001 From: Piotr Jaworski <109736938+pjaworski-rtbh@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:13:53 +0200 Subject: [PATCH 198/272] RTBHouse: Extract tagid from imp fields (#4624) --- adapters/rtbhouse/rtbhouse.go | 62 +++++---- .../exemplary/ae-igs-removal.json | 3 +- .../exemplary/app-with-publisher.json | 3 +- .../rtbhousetest/exemplary/app_banner.json | 3 +- .../rtbhousetest/exemplary/app_native.json | 3 +- .../exemplary/banner-resolve-macros.json | 3 +- .../bidfloor-as-bidder-param-without-cur.json | 3 +- .../exemplary/bidfloor-as-bidder-param.json | 3 +- .../bidfloor-as-impbidfloor-with-cur.json | 3 +- .../bidfloor-as-impbidfloor-without-cur.json | 3 +- .../existing-site-publisher-override.json | 3 +- .../multiple-imps-different-publishers.json | 6 +- .../native-with-deprecated-native-prop.json | 3 +- .../native-with-proper-native-response.json | 3 +- .../exemplary/pmp-removal-test.json | 3 +- .../exemplary/simple-banner-paapi.json | 3 +- .../rtbhousetest/exemplary/simple-banner.json | 3 +- .../exemplary/tagid-from-adserver-adslot.json | 123 ++++++++++++++++++ .../exemplary/tagid-from-pbadslot.json | 119 +++++++++++++++++ .../tagid-precedence-gpid-over-pbadslot.json | 122 +++++++++++++++++ .../tagid-preservation-existing.json | 116 +++++++++++++++++ ...bidfloors-given-param-and-impbidfloor.json | 3 +- .../supplemental/bad_response.json | 3 +- ...ner-native-req-faulty-mtype-in-native.json | 6 +- .../native-with-faulty-adm-native-prop.json | 3 +- .../native-with-faulty-adm-response.json | 3 +- .../supplemental/simple-banner-bad-mtype.json | 3 +- .../supplemental/simple-banner-no-mtype.json | 3 +- .../rtbhousetest/supplemental/status_204.json | 3 +- .../rtbhousetest/supplemental/status_400.json | 3 +- .../rtbhousetest/supplemental/status_418.json | 3 +- 31 files changed, 576 insertions(+), 50 deletions(-) create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-adserver-adslot.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-pbadslot.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/tagid-precedence-gpid-over-pbadslot.json create mode 100644 adapters/rtbhouse/rtbhousetest/exemplary/tagid-preservation-existing.json diff --git a/adapters/rtbhouse/rtbhouse.go b/adapters/rtbhouse/rtbhouse.go index 757780b95d..03432e55c1 100644 --- a/adapters/rtbhouse/rtbhouse.go +++ b/adapters/rtbhouse/rtbhouse.go @@ -59,7 +59,15 @@ func (adapter *RTBHouseAdapter) MakeRequests( var publisherId string for _, imp := range openRTBRequest.Imp { - rtbhouseExt, err := getImpressionExt(imp) + var impExtMap map[string]interface{} + err := jsonutil.Unmarshal(imp.Ext, &impExtMap) + if err != nil { + return nil, []error{&errortypes.BadInput{ + Message: "Bidder extension not provided or can't be unmarshalled", + }} + } + + rtbhouseExt, err := getImpressionExt(imp.Ext) if err != nil { return nil, []error{err} } @@ -100,9 +108,13 @@ func (adapter *RTBHouseAdapter) MakeRequests( imp.BidFloor = bidFloor } - // remove PAAPI signals from imp.Ext. RTB House pauses PAAPI support, - // the bidder should not get any PAAPI signals - newImpExt, err := clearAuctionEnvironment(&imp) + if imp.TagID == "" { + imp.TagID = getTagIDFromImpExt(impExtMap, imp.ID) + } + + // remove PAAPI signals + clearAuctionEnvironment(impExtMap) + newImpExt, err := jsonutil.Marshal(impExtMap) if err != nil { errs = append(errs, err) return nil, errs @@ -199,32 +211,39 @@ func setPublisherID(request *openrtb2.BidRequest, publisherId string) error { return nil } -func clearAuctionEnvironment(imp *openrtb2.Imp) (json.RawMessage, error) { - var objmap map[string]interface{} - err := json.Unmarshal(imp.Ext, &objmap) - if err != nil { - return nil, err - } - +func clearAuctionEnvironment(impExtMap map[string]interface{}) { keysToDelete := []string{"ae", "igs", "paapi"} for _, key := range keysToDelete { - _, exists := objmap[key] - if exists { - delete(objmap, key) - } + delete(impExtMap, key) } +} - newImpExt, err := json.Marshal(objmap) - if err != nil { - return nil, err +func getTagIDFromImpExt(impExtMap map[string]interface{}, impID string) string { + if gpid, ok := impExtMap["gpid"].(string); ok && gpid != "" { + return gpid } - return newImpExt, nil + dataMap, hasData := impExtMap["data"].(map[string]interface{}) + if hasData { + // imp.ext.data.adserver.adslot + if adserver, ok := dataMap["adserver"].(map[string]interface{}); ok { + if adslot, ok := adserver["adslot"].(string); ok && adslot != "" { + return adslot + } + } + + if pbAdSlot, ok := dataMap["pbadslot"].(string); ok && pbAdSlot != "" { + return pbAdSlot + } + } + + // imp.ID as fallback + return impID } -func getImpressionExt(imp openrtb2.Imp) (*openrtb_ext.ExtImpRTBHouse, error) { +func getImpressionExt(impExt json.RawMessage) (*openrtb_ext.ExtImpRTBHouse, error) { var bidderExt adapters.ExtImpBidder - if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + if err := jsonutil.Unmarshal(impExt, &bidderExt); err != nil { return nil, &errortypes.BadInput{ Message: "Bidder extension not provided or can't be unmarshalled", } @@ -236,7 +255,6 @@ func getImpressionExt(imp openrtb2.Imp) (*openrtb_ext.ExtImpRTBHouse, error) { Message: "Error while unmarshaling bidder extension", } } - return &rtbhouseExt, nil } diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json b/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json index 7cf35414aa..bfb2c55af5 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/ae-igs-removal.json @@ -36,6 +36,7 @@ ], "imp": [ { + "id": "test-imp-id", "banner": { "format": [ { @@ -50,7 +51,7 @@ }, "someOtherField": "should-remain" }, - "id": "test-imp-id" + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json b/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json index d53ab37f2d..6ccac25098 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app-with-publisher.json @@ -59,7 +59,8 @@ "publisherId": "app-publisher-123" } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json b/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json index ba14e50d88..8a39951ee9 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json @@ -49,7 +49,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" }] }, "impIDs":["test-imp-id"] diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json b/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json index bdd5e57350..272a10f5a1 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json @@ -43,7 +43,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" } ], "app": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/banner-resolve-macros.json b/adapters/rtbhouse/rtbhousetest/exemplary/banner-resolve-macros.json index eaa3965040..55c054d545 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/banner-resolve-macros.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/banner-resolve-macros.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" }] }, "impIDs":["test-imp-id"] diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json index d31110cb3e..a9ede9271e 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param-without-cur.json @@ -60,7 +60,8 @@ "bidfloor": 3.00 } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json index fd324fb034..bdc7eed6be 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-bidder-param.json @@ -63,7 +63,8 @@ "bidfloor": 2 } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json index 24cc0822dd..97c9f2e59c 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-with-cur.json @@ -60,7 +60,8 @@ "publisherId": "12345" } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json index e579017c07..139a492ce5 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/bidfloor-as-impbidfloor-without-cur.json @@ -58,7 +58,8 @@ "publisherId": "12345" } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json b/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json index 235e2c4a8b..a45e84bb7b 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/existing-site-publisher-override.json @@ -63,7 +63,8 @@ "publisherId": "new-publisher-123" } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json b/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json index 3cb44d5422..70cfc797b3 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/multiple-imps-different-publishers.json @@ -60,7 +60,8 @@ "publisherId": "first-publisher" } }, - "id": "test-imp-id-1" + "id": "test-imp-id-1", + "tagid": "test-imp-id-1" }, { "banner": { @@ -76,7 +77,8 @@ "publisherId": "second-publisher" } }, - "id": "test-imp-id-2" + "id": "test-imp-id-2", + "tagid": "test-imp-id-2" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/native-with-deprecated-native-prop.json b/adapters/rtbhouse/rtbhousetest/exemplary/native-with-deprecated-native-prop.json index a4aa158053..ca898872a6 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/native-with-deprecated-native-prop.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/native-with-deprecated-native-prop.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/native-with-proper-native-response.json b/adapters/rtbhouse/rtbhousetest/exemplary/native-with-proper-native-response.json index 232a102ce7..5f5f6f1a2c 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/native-with-proper-native-response.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/native-with-proper-native-response.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json b/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json index 0d31ef3d5b..3b05d5c587 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/pmp-removal-test.json @@ -53,7 +53,8 @@ "publisherId": "12345" } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json index fb96bdff14..1a561ab573 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner-paapi.json @@ -45,7 +45,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" }] }, "impIDs":["test-imp-id"] diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner.json b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner.json index 0cad5a6b96..61923eb38e 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/simple-banner.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" }] }, "impIDs":["test-imp-id"] diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-adserver-adslot.json b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-adserver-adslot.json new file mode 100644 index 0000000000..e069a1fd84 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-adserver-adslot.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "data": { + "adserver": { + "adslot": "adserver_slot_value" + } + }, + "bidder": { + "publisherId": "12345" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + }, + "data": { + "adserver": { + "adslot": "adserver_slot_value" + } + } + }, + "id": "test-imp-id", + "tagid": "adserver_slot_value" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-pbadslot.json b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-pbadslot.json new file mode 100644 index 0000000000..2fa2988764 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-from-pbadslot.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "data": { + "pbadslot": "pbslot_value" + }, + "bidder": { + "publisherId": "12345" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + }, + "data": { + "pbadslot": "pbslot_value" + } + }, + "id": "test-imp-id", + "tagid": "pbslot_value" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/tagid-precedence-gpid-over-pbadslot.json b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-precedence-gpid-over-pbadslot.json new file mode 100644 index 0000000000..df1b7c3faf --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-precedence-gpid-over-pbadslot.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "gpid": "gpid_value", + "data": { + "pbadslot": "pbslot_value" + }, + "bidder": { + "publisherId": "12345" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + }, + "gpid": "gpid_value", + "data": { + "pbadslot": "pbslot_value" + } + }, + "id": "test-imp-id", + "tagid": "gpid_value" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/tagid-preservation-existing.json b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-preservation-existing.json new file mode 100644 index 0000000000..785991f05b --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/tagid-preservation-existing.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "existing_tag", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "gpid": "gpid_value", + "bidder": { + "publisherId": "12345" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "12345" + }, + "gpid": "gpid_value" + }, + "id": "test-imp-id", + "tagid": "existing_tag" + } + ], + "site": { + "publisher": { + "ext": { + "prebid": { + "publisherId": "12345" + } + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 300, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json b/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json index 71b95d18db..e1389acece 100644 --- a/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json +++ b/adapters/rtbhouse/rtbhousetest/exemplary/two-bidfloors-given-param-and-impbidfloor.json @@ -62,7 +62,8 @@ "bidfloor": 2 } }, - "id": "test-imp-id" + "id": "test-imp-id", + "tagid": "test-imp-id" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/bad_response.json b/adapters/rtbhouse/rtbhousetest/supplemental/bad_response.json index a2d0c8da3d..dc61c6d061 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/bad_response.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/bad_response.json @@ -41,7 +41,8 @@ "ext": { "bidder": { } - } + }, + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/banner-native-req-faulty-mtype-in-native.json b/adapters/rtbhouse/rtbhousetest/supplemental/banner-native-req-faulty-mtype-in-native.json index 4f643d1842..9229cd58ec 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/banner-native-req-faulty-mtype-in-native.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/banner-native-req-faulty-mtype-in-native.json @@ -49,7 +49,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" }, { "id": "test-banner-imp", @@ -61,7 +62,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-banner-imp" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-native-prop.json b/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-native-prop.json index bfdf568d3c..99dc0bcbb9 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-native-prop.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-native-prop.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-response.json b/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-response.json index 4e95d2e23c..6a1c564e46 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-response.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/native-with-faulty-adm-response.json @@ -37,7 +37,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-native-imp" } ], "site": { diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-bad-mtype.json b/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-bad-mtype.json index 3b92e5d8fd..385f807a49 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-bad-mtype.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-bad-mtype.json @@ -46,7 +46,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-no-mtype.json b/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-no-mtype.json index 58bdab87eb..d73090b0b1 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-no-mtype.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/simple-banner-no-mtype.json @@ -46,7 +46,8 @@ }, "ext": { "bidder": {} - } + }, + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/status_204.json b/adapters/rtbhouse/rtbhousetest/supplemental/status_204.json index 03a69c2617..8258d37698 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/status_204.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/status_204.json @@ -41,7 +41,8 @@ "ext": { "bidder": { } - } + }, + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/status_400.json b/adapters/rtbhouse/rtbhousetest/supplemental/status_400.json index 25f8778636..06fcf177af 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/status_400.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/status_400.json @@ -41,7 +41,8 @@ "ext": { "bidder": { } - } + }, + "tagid": "test-imp-id" } ] }, diff --git a/adapters/rtbhouse/rtbhousetest/supplemental/status_418.json b/adapters/rtbhouse/rtbhousetest/supplemental/status_418.json index 27073b0e0c..f27138969d 100644 --- a/adapters/rtbhouse/rtbhousetest/supplemental/status_418.json +++ b/adapters/rtbhouse/rtbhousetest/supplemental/status_418.json @@ -41,7 +41,8 @@ "ext": { "bidder": { } - } + }, + "tagid": "test-imp-id" } ] }, From 563940c47ac5c00db09822ce208b9e4b7304c9db Mon Sep 17 00:00:00 2001 From: Mikael Lundin <mikael-lundin@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:30:03 +0200 Subject: [PATCH 199/272] Adnuntius: Send EIDs in URL instead of body (#4632) --- adapters/adnuntius/adnuntius.go | 23 ++-- adapters/adnuntius/adnuntius_utils.go | 18 ++- .../check-eids-parameter-and-userId.json | 125 ++++++++++++++++++ .../supplemental/check-eids-parameter.json | 122 +++++++++++++++++ ...t.json => check-empty-eids-parameter.json} | 13 +- .../supplemental/user-ext-invalid.json | 2 +- 6 files changed, 276 insertions(+), 27 deletions(-) create mode 100644 adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter-and-userId.json create mode 100644 adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter.json rename adapters/adnuntius/adnuntiustest/supplemental/{user-ext.json => check-empty-eids-parameter.json} (90%) diff --git a/adapters/adnuntius/adnuntius.go b/adapters/adnuntius/adnuntius.go index 7b0f8f3831..f5c55be74e 100644 --- a/adapters/adnuntius/adnuntius.go +++ b/adapters/adnuntius/adnuntius.go @@ -101,8 +101,15 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters } } + var extUser openrtb_ext.ExtUser + if ortbRequest.User != nil && ortbRequest.User.Ext != nil { + if err := jsonutil.Unmarshal(ortbRequest.User.Ext, &extUser); err != nil { + return nil, []error{fmt.Errorf("failed to parse Ext User: %w", err)} + } + } + + endpoint, err := makeEndpointUrl(ortbRequest, a, noCookies, extUser) - endpoint, err := makeEndpointUrl(ortbRequest, a, noCookies) if err != nil { return nil, []error{&errortypes.BadInput{ Message: fmt.Sprintf("failed to parse URL: %s", err), @@ -119,13 +126,6 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters return nil, []error{fmt.Errorf("failed to parse site Ext: %v", err)} } - var extUser openrtb_ext.ExtUser - if ortbRequest.User != nil && ortbRequest.User.Ext != nil { - if err := jsonutil.Unmarshal(ortbRequest.User.Ext, &extUser); err != nil { - return nil, []error{fmt.Errorf("failed to parse Ext User: %v", err)} - } - } - for _, networkAdunits := range networkAdunitMap { adnuntiusRequest := adnRequest{ @@ -134,13 +134,6 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters KeyValues: extSite.Data, } - // Will change when our adserver can accept multiple user IDS - if extUser.Eids != nil && len(extUser.Eids) > 0 { - if len(extUser.Eids[0].UIDs) > 0 { - adnuntiusRequest.MetaData.Usi = extUser.Eids[0].UIDs[0].ID - } - } - ortbUser := ortbRequest.User if ortbUser != nil { ortbUserId := ortbRequest.User.ID diff --git a/adapters/adnuntius/adnuntius_utils.go b/adapters/adnuntius/adnuntius_utils.go index 562a0a3bf1..4a2d234ba2 100644 --- a/adapters/adnuntius/adnuntius_utils.go +++ b/adapters/adnuntius/adnuntius_utils.go @@ -32,7 +32,7 @@ func setHeaders(ortbRequest openrtb2.BidRequest) http.Header { return headers } -func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool) (string, []error) { +func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool, extUser openrtb_ext.ExtUser) (string, []error) { uri, err := url.Parse(a.endpoint) if err != nil { return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)} @@ -80,6 +80,22 @@ func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool q.Set("noCookies", "true") } + if len(extUser.Eids) > 0 { + hasValidEid := false + for _, eid := range extUser.Eids { + if len(eid.UIDs) > 0 { + hasValidEid = true + break + } + } + if hasValidEid { + eidsJSON, err := jsonutil.Marshal(extUser.Eids) + if err == nil { + q.Set("eids", string(eidsJSON)) + } + } + } + q.Set("tzo", strconv.Itoa(tzo)) q.Set("format", "prebidServer") diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter-and-userId.json b/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter-and-userId.json new file mode 100644 index 0000000000..2c9e41ae66 --- /dev/null +++ b/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter-and-userId.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "id": "1kjh3429kjh295jkl", + "ext":{ + "eids" : [ + { + "source": "adserver.org", + "uids": [ + { "id": "111111111111", "atype": 1, "ext": { "rtiPartner": "TDID" } } + ] + }, + { + "source": "pubcid.org", + "uids": [ + { "id": "22222222-2222-2222-2222-222222222222", "atype": 1 } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "auId": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://whatever.url?eids=%5B%7B%22source%22%3A%22adserver.org%22%2C%22uids%22%3A%5B%7B%22id%22%3A%22111111111111%22%2C%22atype%22%3A1%2C%22ext%22%3A%7B+%22rtiPartner%22%3A+%22TDID%22+%7D%7D%5D%7D%2C%7B%22source%22%3A%22pubcid.org%22%2C%22uids%22%3A%5B%7B%22id%22%3A%2222222222-2222-2222-2222-222222222222%22%2C%22atype%22%3A1%7D%5D%7D%5D&format=prebidServer&tzo=0", + "body": { + "adUnits": [ + { + "auId": "123", + "targetId": "123-test-imp-id:banner", + "nativeRequest": {}, + "dimensions": [[300,250],[300,600]] + } + ], + "metaData": { + "usi": "1kjh3429kjh295jkl" + }, + "context": "unknown" + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "adUnits": [ + { + "auId": "0000000000000123", + "targetId": "123-test-imp-id:banner", + "matchedAdCount": 1, + "html": "<ADCODE>", + "responseId": "adn-rsp-900646517", + "ads": [ + { + "destinationUrls": { + "url": "http://www.google.com" + }, + "advertiserDomains": ["google.com"], + "bid": { + "amount": 20.0, + "currency": "NOK" + }, + "adId": "adn-id-1559784094", + "creativeWidth": "980", + "creativeHeight": "240", + "creativeId": "jn9hpzvlsf8cpdmm", + "lineItemId": "q7y9qm5b0xt9htrv" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "adn-id-1559784094", + "impid": "test-imp-id", + "price": 20000, + "adm": "<ADCODE>", + "adid": "adn-id-1559784094", + "adomain": [ + "google.com" + ], + "cid": "q7y9qm5b0xt9htrv", + "crid": "jn9hpzvlsf8cpdmm", + "mtype": 1, + "w": 980, + "h": 240 + }, + "type": "banner" + } + ], + "currency": "NOK" + } + ] +} + diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter.json b/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter.json new file mode 100644 index 0000000000..484b0637b2 --- /dev/null +++ b/adapters/adnuntius/adnuntiustest/supplemental/check-eids-parameter.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "ext":{ + "eids" : [ + { + "source": "adserver.org", + "uids": [ + { "id": "111111111111", "atype": 1, "ext": { "rtiPartner": "TDID" } } + ] + }, + { + "source": "pubcid.org", + "uids": [ + { "id": "22222222-2222-2222-2222-222222222222", "atype": 1 } + ] + } + ] + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "auId": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://whatever.url?eids=%5B%7B%22source%22%3A%22adserver.org%22%2C%22uids%22%3A%5B%7B%22id%22%3A%22111111111111%22%2C%22atype%22%3A1%2C%22ext%22%3A%7B+%22rtiPartner%22%3A+%22TDID%22+%7D%7D%5D%7D%2C%7B%22source%22%3A%22pubcid.org%22%2C%22uids%22%3A%5B%7B%22id%22%3A%2222222222-2222-2222-2222-222222222222%22%2C%22atype%22%3A1%7D%5D%7D%5D&format=prebidServer&tzo=0", + "body": { + "adUnits": [ + { + "auId": "123", + "targetId": "123-test-imp-id:banner", + "nativeRequest": {}, + "dimensions": [[300,250],[300,600]] + } + ], + "metaData": {}, + "context": "unknown" + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "adUnits": [ + { + "auId": "0000000000000123", + "targetId": "123-test-imp-id:banner", + "matchedAdCount": 1, + "html": "<ADCODE>", + "responseId": "adn-rsp-900646517", + "ads": [ + { + "destinationUrls": { + "url": "http://www.google.com" + }, + "advertiserDomains": ["google.com"], + "bid": { + "amount": 20.0, + "currency": "NOK" + }, + "adId": "adn-id-1559784094", + "creativeWidth": "980", + "creativeHeight": "240", + "creativeId": "jn9hpzvlsf8cpdmm", + "lineItemId": "q7y9qm5b0xt9htrv" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "adn-id-1559784094", + "impid": "test-imp-id", + "price": 20000, + "adm": "<ADCODE>", + "adid": "adn-id-1559784094", + "adomain": [ + "google.com" + ], + "cid": "q7y9qm5b0xt9htrv", + "crid": "jn9hpzvlsf8cpdmm", + "mtype": 1, + "w": 980, + "h": 240 + }, + "type": "banner" + } + ], + "currency": "NOK" + } + ] +} + diff --git a/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/check-empty-eids-parameter.json similarity index 90% rename from adapters/adnuntius/adnuntiustest/supplemental/user-ext.json rename to adapters/adnuntius/adnuntiustest/supplemental/check-empty-eids-parameter.json index 4d3ccb1373..379a77b9f8 100644 --- a/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json +++ b/adapters/adnuntius/adnuntiustest/supplemental/check-empty-eids-parameter.json @@ -4,12 +4,6 @@ "user": { "ext":{ "eids" : [ - { - "source": "idProvider", - "uids": [ - { "id": "userId", "atype": 1, "ext": { "stype": "ppuid" } } - ] - } ] } }, @@ -48,10 +42,8 @@ "nativeRequest": {}, "dimensions": [[300,250],[300,600]] } - ], - "metaData": { - "usi": "userId" - }, + ], + "metaData": {}, "context": "unknown" }, "impIDs":["test-imp-id"] @@ -115,3 +107,4 @@ } ] } + diff --git a/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json b/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json index 3e71a4f1ac..1867dd3306 100644 --- a/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json +++ b/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json @@ -29,7 +29,7 @@ }, "expectedMakeRequestsErrors": [ { - "value": "failed to parse URL: [failed to parse GDPR information: failed to parse ExtUser in Adnuntius GDPR check: expect { or n, but found \"]", + "value": "failed to parse Ext User: expect { or n, but found \"", "comparison": "literal" } ] From e3b3d452c77ae233d7ab9113e64e8c36e8ce4eeb Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:26:21 +0300 Subject: [PATCH 200/272] New Adapter: Adsmovil (#4712) Co-authored-by: adsmovil <prebid@adsmovil.com> --- static/bidder-info/adsmovil.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 static/bidder-info/adsmovil.yaml diff --git a/static/bidder-info/adsmovil.yaml b/static/bidder-info/adsmovil.yaml new file mode 100644 index 0000000000..2e919de4c6 --- /dev/null +++ b/static/bidder-info/adsmovil.yaml @@ -0,0 +1,16 @@ +aliasOf: "teqblaze" +endpoint: "https://tag-ssp.adsmovil.com/pserver" +maintainer: + email: "prebid@adsmovil.com" +capabilities: + site: + mediaTypes: + - banner + - video + - native + + app: + mediaTypes: + - banner + - video + - native \ No newline at end of file From 8ce84023c3e68a69d9e3ec1fd3f0e31a61c04c86 Mon Sep 17 00:00:00 2001 From: Luca Corbo <lu.corbo@gmail.com> Date: Wed, 15 Apr 2026 23:01:16 +0200 Subject: [PATCH 201/272] New Module: WURFL Device Enrichment Module (#4158) Co-authored-by: lucor-sm <lucor@scientiamobile.com> --- go.mod | 3 +- go.sum | 5 +- modules/builder.go | 4 + .../wurfl_devicedetection/README.md | 357 ++++++++++++ .../wurfl_devicedetection/config.go | 58 ++ .../wurfl_devicedetection/config_test.go | 121 ++++ .../wurfl_devicedetection/libwurfl/.gitignore | 3 + .../wurfl_devicedetection/module.go | 181 ++++++ .../wurfl_devicedetection/module_test.go | 537 ++++++++++++++++++ .../module_wurfl_test.go | 59 ++ .../sample/pbs_example.json | 68 +++ .../sample/request_data.json | 119 ++++ .../wurfl_devicedetection/wurfl_data.go | 86 +++ .../wurfl_devicedetection/wurfl_data_test.go | 145 +++++ .../wurfl_devicedetection/wurfl_engine.go | 145 +++++ .../wurfl_engine_fallback.go | 11 + .../wurfl_engine_fallback_test.go | 14 + .../wurfl_devicedetection/wurfl_enricher.go | 194 +++++++ .../wurfl_enricher_test.go | 213 +++++++ .../wurfl_devicedetection/wurfl_headers.go | 104 ++++ .../wurfl_headers_test.go | 171 ++++++ 21 files changed, 2596 insertions(+), 2 deletions(-) create mode 100644 modules/scientiamobile/wurfl_devicedetection/README.md create mode 100644 modules/scientiamobile/wurfl_devicedetection/config.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/config_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/libwurfl/.gitignore create mode 100644 modules/scientiamobile/wurfl_devicedetection/module.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/module_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/module_wurfl_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/sample/pbs_example.json create mode 100644 modules/scientiamobile/wurfl_devicedetection/sample/request_data.json create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_data.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_data_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_engine.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_enricher.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_enricher_test.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_headers.go create mode 100644 modules/scientiamobile/wurfl_devicedetection/wurfl_headers_test.go diff --git a/go.mod b/go.mod index ec92fd3eed..998750a0ab 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/IABTechLab/adscert v0.34.0 github.com/NYTimes/gziphandler v1.1.1 + github.com/WURFL/golang-wurfl v1.30.3 github.com/alitto/pond v1.8.3 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/benbjohnson/clock v1.3.0 @@ -33,7 +34,7 @@ require ( github.com/rs/cors v1.11.0 github.com/spf13/cast v1.5.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.1 github.com/tidwall/sjson v1.2.5 github.com/vrischmann/go-metrics-influxdb v0.1.1 diff --git a/go.sum b/go.sum index 5398b2d6b1..2d03cb08c4 100644 --- a/go.sum +++ b/go.sum @@ -61,6 +61,8 @@ github.com/IABTechLab/adscert v0.34.0/go.mod h1:pCLd3Up1kfTrH6kYFUGGeavxIc1f6Tvv github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/WURFL/golang-wurfl v1.30.3 h1:a/ZR+/mwMrA9cEVa88ig47zkVJNl3HM5OTCpPvoSYmE= +github.com/WURFL/golang-wurfl v1.30.3/go.mod h1:cKXIyA0oIrbZ7YTOhBPX29ELt6XAM1/S7qyFIrTKkS0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -484,8 +486,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= diff --git a/modules/builder.go b/modules/builder.go index 034ac16ab5..df2f1b1c3a 100644 --- a/modules/builder.go +++ b/modules/builder.go @@ -4,6 +4,7 @@ import ( fiftyonedegreesDevicedetection "github.com/prebid/prebid-server/v4/modules/fiftyonedegrees/devicedetection" prebidOrtb2blocking "github.com/prebid/prebid-server/v4/modules/prebid/ortb2blocking" prebidRulesengine "github.com/prebid/prebid-server/v4/modules/prebid/rulesengine" + wurflDevicedetection "github.com/prebid/prebid-server/v4/modules/scientiamobile/wurfl_devicedetection" scope3Rtd "github.com/prebid/prebid-server/v4/modules/scope3/rtd" ) @@ -18,6 +19,9 @@ func builders() ModuleBuilders { "ortb2blocking": prebidOrtb2blocking.Builder, "rulesengine": prebidRulesengine.Builder, }, + "scientiamobile": { + "wurfl_devicedetection": wurflDevicedetection.Builder, + }, "scope3": { "rtd": scope3Rtd.Builder, }, diff --git a/modules/scientiamobile/wurfl_devicedetection/README.md b/modules/scientiamobile/wurfl_devicedetection/README.md new file mode 100644 index 0000000000..023b5828d2 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/README.md @@ -0,0 +1,357 @@ +## WURFL Device Enrichment Module + +### Overview + +The **WURFL Device Enrichment Module** for Prebid Server enhances the OpenRTB 2.x payload +with comprehensive device detection data powered by **ScientiaMobile**’s WURFL device detection framework. +Thanks to WURFL's device database, the module provides accurate and comprehensive device-related information, +enabling bidders to make better-informed targeting and optimization decisions. + +### Key features + +#### Device Field Enrichment + +The WURFL module populates **missing or empty fields** in `ortb2.device` with the following data: + +- **make**: Manufacturer of the device (e.g., "Apple", "Samsung"). +- **model**: Device model (e.g., "iPhone 14", "Galaxy S22"). +- **os**: Operating system (e.g., "iOS", "Android"). +- **osv**: Operating system version (e.g., "16.0", "12.0"). +- **h**: Screen height in pixels. +- **w**: Screen width in pixels. +- **ppi**: Screen pixels per inch (PPI). +- **pxratio**: Screen pixel density ratio. +- **devicetype**: Device type (e.g., mobile, tablet, desktop). +- **js**: Support for JavaScript, where 0 = no, 1 = yes + +> **Note**: If these fields are already populated in the bid request, the module will not overwrite them. + +#### Publisher-Specific Enrichment + +Device enrichment is selectively enabled for publishers based on their **account ID**. +The module identifies publishers through the following fields: + +- `site.publisher.id` (for web environments). +- `app.publisher.id` (for mobile app environments). +- `dooh.publisher.id` (for digital out-of-home environments). + +### Build prerequisites + +To build the WURFL module, you need to install the WURFL Infuze from ScientiaMobile. +For more details, visit: [ScientiaMobile WURFL Infuze](https://docs.scientiamobile.com/documentation/infuze/infuze-c-api-user-guide). + +#### Note + +The WURFL module requires CGO at compile time to link against the WURFL Infuze library. + +To enable the WURFL module, the `wurfl` build tag must be specified: + +```go +go build -tags wurfl . +``` + +If the `wurfl` tag is not provided, the module will fail to initialize at startup. + +### Configuring the WURFL Module + +Below is a sample configuration for the WURFL module: + +```json +{ + "adapters": [ + { + "appnexus": { + "enabled": true + } + } + ], + "gdpr": { + "enabled": true, + "default_value": 0, + "timeouts_ms": { + "active_vendorlist_fetch": 900000 + } + }, + "hooks": { + "enabled": true, + "modules": { + "scientiamobile": { + "wurfl_devicedetection": { + "enabled": true, + "wurfl_file_path": "/path/to/wurfl.zip", + "wurfl_snapshot_url": "<wurfl_snapshot_url>", + "wurfl_cache_size": 200000, + "allowed_publisher_ids": ["1","3"], + "ext_caps": true + } + } + }, + "host_execution_plan": { + "endpoints": { + "/openrtb2/auction": { + "stages": { + "entrypoint": { + "groups": [ + { + "timeout": 10, + "hook_sequence": [ + { + "module_code": "scientiamobile.wurfl_devicedetection", + "hook_impl_code": "scientiamobile-wurfl_devicedetection-entrypoint-hook" + } + ] + } + ] + }, + "raw_auction_request": { + "groups": [ + { + "timeout": 10, + "hook_sequence": [ + { + "module_code": "scientiamobile.wurfl_devicedetection", + "hook_impl_code": "scientiamobile-wurfl_devicedetection-raw-auction-request-hook" + } + ] + } + ] + } + } + } + } + } + } +} +``` + +The same configuration in YAML format + +```yaml +adapters: + - appnexus: + enabled: true +gdpr: + enabled: true + default_value: 0 + timeouts_ms: + active_vendorlist_fetch: 900000 +hooks: + enabled: true + modules: + scientiamobile: + wurfl_devicedetection: + enabled: true + wurfl_file_path: "/path/to/wurfl.zip" + wurfl_snapshot_url: "<wurfl_snapshot_url>" + wurfl_cache_size: 200000 + allowed_publisher_ids: + - "1" + - "3" + ext_caps: true + host_execution_plan: + endpoints: + /openrtb2/auction: + stages: + entrypoint: + groups: + - timeout: 10 + hook_sequence: + - module_code: "scientiamobile.wurfl_devicedetection" + hook_impl_code: "scientiamobile-wurfl_devicedetection-entrypoint-hook" + raw_auction_request: + groups: + - timeout: 10 + hook_sequence: + - module_code: "scientiamobile.wurfl_devicedetection" + hook_impl_code: "scientiamobile-wurfl_devicedetection-raw-auction-request-hook" +``` + +### Configuration Options + +| Parameter | Requirement | Description | +|---------------------------|-------------|-------------------------------------------------------------------------------------------------------| +| **`wurfl_file_path`** | Mandatory | Path to the WURFL file (e.g. /path/to/wurfl.zip). | +| **`wurfl_snapshot_url`** | Optional | URL of the licensed WURFL snapshot. If set, it periodically updates the WURFL file in the `wurfl_file_path` directory, which must be writable. | +| **`wurfl_cache_size`** | Optional | Maximum number of devices stored in the WURFL cache. Defaults to the WURFL cache's standard size. | +| **`ext_caps`** | Optional | If `true`, the module adds all licensed capabilities to the `device.ext` object. | +| **`allowed_publisher_ids`** | Optional | List of publisher IDs permitted to use the module. Defaults to all publishers. | + +A valid WURFL license must include all the required capabilities for device enrichment. + +### Launching Prebid Server with the WURFL Module + +1. Download dependencies + +```bash +go mod download +``` + +2. Copy the sample [config file](modules/scientiamobile/wurfl_devicedetection/sample/pbs-example.json) + +```bash +cp modules/scientiamobile/wurfl_devicedetection/sample/pbs-example.json pbs.json +``` + +3. Copy the WURFL file to `wurfl_file_path` + +In order for the WURFL module to work, you need a WURFL file installed on your system. The WURFL Infuze package comes with a recent evaluation copy of the WURFL file called wurfl.zip. + +Commercial licensees of WURFL are granted access to "The Customer Vault", a personal virtual space containing purchased software licenses and weekly updated versions of the WURFL repository. + +For more details, visit: [ScientiaMobile WURFL Infuze](https://docs.scientiamobile.com/documentation/infuze/infuze-c-api-user-guide). + +4. Start the server + + ```bash + go run -tags wurfl . +``` + +When the server starts, it loads the WURFL file from `wurfl_file_path` into the module. +To enable automatic updates, ensure that `wurfl_snapshot_url` is correctly configured. + +Sample request data for testing is available in the module's `sample` directory. +Using the `auction` endpoint, you can observe WURFL-enriched device data in the response. + +### Sample Response + +Using the sample request data via `curl` when the module is configured with `ext_caps` set to `false` (or no value) + +```bash +curl http://localhost:8000/openrtb2/auction --data @modules/scientiamobile/wurfl_devicedetection/sample/request_data.json +``` + +the device object in the response will include WURFL device detection data: + +```json +"device": { + "ua": "Mozilla/5.0 (Linux; Android 15; Pixel 9 Pro XL Build/AP3A.241005.015;) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 EdgA/124.0.2478.64", + "devicetype": 1, + "make": "Google", + "model": "Pixel 9 Pro XL", + "os": "Android", + "osv": "15", + "h": 2992, + "w": 1344, + "ppi": 481, + "pxratio": 2.55, + "js": 1, + "ext": { + "wurfl": { + "wurfl_id": "google_pixel_9_pro_xl_ver1_suban150" + } + } +} +``` + +When `ext_caps` is set to `true`, the response will include all licensed capabilities: + +```json +"device":{ + "ua":"Mozilla/5.0 (Linux; Android 15; Pixel 9 Pro XL Build/AP3A.241005.015; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 EdgA/124.0.2478.64", + "devicetype":1, + "make":"Google", + "model":"Pixel 9 Pro XL", + "os":"Android", + "osv":"15", + "h":2992, + "w":1344, + "ppi":481, + "pxratio":2.55, + "js":1, + "ext":{ + "wurfl":{ + "wurfl_id":"google_pixel_9_pro_xl_ver1_suban150", + "mobile_browser_version":"", + "resolution_height":"2992", + "resolution_width":"1344", + "is_wireless_device":"true", + "is_tablet":"false", + "physical_form_factor":"phone_phablet", + "ajax_support_javascript":"true", + "preferred_markup":"html_web_4_0", + "brand_name":"Google", + "can_assign_phone_number":"true", + "xhtml_support_level":"4", + "ux_full_desktop":"false", + "device_os":"Android", + "physical_screen_width":"71", + "is_connected_tv":"false", + "is_smarttv":"false", + "physical_screen_height":"158", + "model_name":"Pixel 9 Pro XL", + "is_ott":"false", + "density_class":"2.55", + "marketing_name":"", + "device_os_version":"15.0", + "mobile_browser":"Chrome Mobile", + "pointing_method":"touchscreen", + "is_app_webview":"false", + "advertised_app_name":"Edge Browser", + "is_smartphone":"true", + "is_robot":"false", + "advertised_device_os":"Android", + "is_largescreen":"true", + "is_android":"true", + "is_xhtmlmp_preferred":"false", + "device_name":"Google Pixel 9 Pro XL", + "is_ios":"false", + "is_touchscreen":"true", + "is_wml_preferred":"false", + "is_app":"false", + "is_mobile":"true", + "is_phone":"true", + "is_full_desktop":"false", + "is_generic":"false", + "advertised_browser":"Edge", + "complete_device_name":"Google Pixel 9 Pro XL", + "advertised_browser_version":"124.0.2478.64", + "is_html_preferred":"true", + "is_windows_phone":"false", + "pixel_density":"481", + "form_factor":"Smartphone", + "advertised_device_os_version":"15" + } + } +} +``` + +### Building Docker images with WURFL support + +When building Prebid Server with the WURFL module using Docker, you need to install both compile-time and runtime WURFL dependencies. + +To build a Docker image with WURFL support: + +1. **Place the WURFL library package**: Copy the `libwurfl*.deb` package files into the `modules/scientiamobile/wurfl_devicedetection/libwurfl/` directory before building the Docker image. + +2. **Install compile-time dependencies**: In the build stage of your Dockerfile, before the `go build` command, add: + + ```dockerfile + # Installing WURFL compile-time dependencies if libwurfl package is present + RUN if ls modules/scientiamobile/wurfl_devicedetection/libwurfl/libwurfl*.deb 1> /dev/null 2>&1; then \ + dpkg -i modules/scientiamobile/wurfl_devicedetection/libwurfl/libwurfl*.deb; \ + fi + ``` + + And build with the WURFL tag: + + ```dockerfile + RUN go build -tags wurfl -mod=vendor -ldflags "-X github.com/prebid/prebid-server/v4/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/v4/version.Rev=`git rev-parse HEAD`" . + ``` + +3. **Install runtime dependencies**: In the runtime stage, add the WURFL runtime dependencies: + + ```dockerfile + # Installing WURFL runtime dependencies if libwurfl package is present + COPY modules/scientiamobile/wurfl_devicedetection/libwurfl/ /tmp/wurfl + RUN if ls /tmp/wurfl/libwurfl*.deb 1> /dev/null 2>&1; then \ + dpkg -i /tmp/wurfl/libwurfl*.deb; \ + apt-get update && \ + apt-get install -y curl && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*; \ + rm -rf /tmp/wurfl; \ + fi + ``` + +## Maintainer + +<prebid@scientiamobile.com> diff --git a/modules/scientiamobile/wurfl_devicedetection/config.go b/modules/scientiamobile/wurfl_devicedetection/config.go new file mode 100644 index 0000000000..8702e64365 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/config.go @@ -0,0 +1,58 @@ +package wurfl_devicedetection + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +const ( + defaultCacheSize = "200000" +) + +var ErrWURFLFilePathRequired = errors.New("wurfl_file_path is required") + +// newConfig creates and validates a new config from the raw JSON data. +func newConfig(data json.RawMessage) (config, error) { + var cfg config + if err := jsonutil.UnmarshalValid(data, &cfg); err != nil { + return cfg, fmt.Errorf("failed to parse config: %s", err) + } + err := cfg.validate() + return cfg, err +} + +// config represents the configuration for the module. +type config struct { + // WURFLFilePath is the path to the WURFL file (i.e. /path/to/wurfl.zip). Required. + WURFLFilePath string `json:"wurfl_file_path"` + // WURFLSnapshotURL is the URL of the WURFL Snapshot. + // If set, it will be used to periodically update the WURFL file. + // The snapshot will be downloaded to the same directory as the WURFLFilePath. + // Make sure this directory is writable. + WURFLSnapshotURL string `json:"wurfl_snapshot_url"` + // WURFLCacheSize is the size of the WURFL Engine cache. Default is 200000 + WURFLCacheSize int `json:"wurfl_cache_size"` + // Holds the list of allowed publisher IDs. Leave empty to allow all. + AllowedPublisherIDs []string `json:"allowed_publisher_ids"` + // ExtCaps if true will include licensed WURFL capabilities in ortb2.Device.Ext + ExtCaps bool `json:"ext_caps"` +} + +// WURFLEngineCacheSize returns the cache size for the WURFL engine. +func (cfg config) WURFLEngineCacheSize() string { + if cfg.WURFLCacheSize > 0 { + return strconv.Itoa(cfg.WURFLCacheSize) + } + return defaultCacheSize +} + +func (cfg config) validate() error { + if cfg.WURFLFilePath == "" { + return ErrWURFLFilePathRequired + } + return nil +} diff --git a/modules/scientiamobile/wurfl_devicedetection/config_test.go b/modules/scientiamobile/wurfl_devicedetection/config_test.go new file mode 100644 index 0000000000..fba8845efb --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/config_test.go @@ -0,0 +1,121 @@ +package wurfl_devicedetection + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewConfig(t *testing.T) { + tests := []struct { + name string + input json.RawMessage + expectedErr bool + validate func(t *testing.T, cfg config) + }{ + { + name: "Valid config with default cache size", + input: json.RawMessage(`{ + "wurfl_snapshot_url": "http://example.com/wurfl-data", + "wurfl_file_path": "/tmp/wurfl.zip" + }`), + expectedErr: false, + validate: func(t *testing.T, cfg config) { + assert.Equal(t, "http://example.com/wurfl-data", cfg.WURFLSnapshotURL) + assert.Equal(t, "/tmp/wurfl.zip", cfg.WURFLFilePath) + assert.Equal(t, defaultCacheSize, cfg.WURFLEngineCacheSize()) + }, + }, + { + name: "Valid config with custom cache size", + input: json.RawMessage(`{ + "wurfl_snapshot_url": "http://example.com/wurfl-data", + "wurfl_file_path": "/tmp/wurfl.zip", + "wurfl_cache_size": 5000, + "wurfl_run_updater": true + }`), + expectedErr: false, + validate: func(t *testing.T, cfg config) { + assert.Equal(t, "5000", cfg.WURFLEngineCacheSize()) + }, + }, + { + name: "Invalid config - missing wurfl_snapshot_url", + input: json.RawMessage(`{ + "wurfl_file_path": "/tmp/wurfl" + }`), + expectedErr: false, + }, + { + name: "Invalid config - missing wurfl_file_path", + input: json.RawMessage(`{ + "wurfl_snapshot_url": "http://example.com/wurfl-data" + }`), + expectedErr: true, + }, + { + name: "Invalid config - malformed JSON", + input: json.RawMessage(`{ "wurfl_snapshot_url": "http://example.com/wurfl-data", "wurfl_file_path": "/tmp/wurfl",`), // Malformed JSON + expectedErr: true, + }, + { + name: "Empty config", + input: json.RawMessage(`{}`), + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + cfg, err := newConfig(tc.input) + + if tc.expectedErr { + assert.Error(t, err) + return + } + + assert.NoError(t, err) + if tc.validate != nil { + tc.validate(t, cfg) + } + }) + } +} + +func TestValidate(t *testing.T) { + tests := []struct { + name string + cfg config + expectedErr bool + }{ + { + name: "Valid config", + cfg: config{ + WURFLSnapshotURL: "http://example.com/wurfl-data", + WURFLFilePath: "/tmp/wurfl.zip", + }, + expectedErr: false, + }, + { + name: "Invalid config - missing wurfl_file_path", + cfg: config{ + WURFLSnapshotURL: "http://example.com/wurfl-data", + }, + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.cfg.validate() + + if tc.expectedErr { + assert.Error(t, err) + return + } + + assert.NoError(t, err) + }) + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/libwurfl/.gitignore b/modules/scientiamobile/wurfl_devicedetection/libwurfl/.gitignore new file mode 100644 index 0000000000..a5baada18f --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/libwurfl/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/modules/scientiamobile/wurfl_devicedetection/module.go b/modules/scientiamobile/wurfl_devicedetection/module.go new file mode 100644 index 0000000000..53bb26e74d --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/module.go @@ -0,0 +1,181 @@ +package wurfl_devicedetection + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/buger/jsonparser" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/hooks/hookexecution" + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/tidwall/sjson" +) + +const ( + wurflHeaderCtxKey = "wurfl_header" +) + +// declare conformity with hookstage.RawAuctionRequest interface +var ( + _ hookstage.RawAuctionRequest = Module{} + _ hookstage.Entrypoint = Module{} +) + +// payloadPublisherIDPaths specifies the possible paths in the Request payload JSON +// where the publisher ID can be defined. +var payloadPublisherIDPaths = [][]string{ + {"site", "publisher", "id"}, + {"app", "publisher", "id"}, + {"dooh", "publisher", "id"}, +} + +func Builder(configRaw json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { + cfg, err := newConfig(configRaw) + if err != nil { + return nil, err + } + + we, err := newWurflEngine(cfg) + if err != nil { + return nil, err + } + + m := Module{ + we: we, + extCaps: cfg.ExtCaps, + } + if len(cfg.AllowedPublisherIDs) > 0 { + m.allowedPublisherIDs = make(map[string]struct{}, len(cfg.AllowedPublisherIDs)) + for _, v := range cfg.AllowedPublisherIDs { + m.allowedPublisherIDs[v] = struct{}{} + } + } + return m, nil +} + +// Module must implement at least 1 hook interface. +type Module struct { + we wurflDeviceDetection + allowedPublisherIDs map[string]struct{} + extCaps bool +} + +// HandleEntrypointHook implements hookstage.Entrypoint. +func (m Module) HandleEntrypointHook(ctx context.Context, invocationCtx hookstage.ModuleInvocationContext, payload hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { + result := hookstage.HookResult[hookstage.EntrypointPayload]{} + if !m.isPublisherAllowed(payload.Body) { + return result, hookexecution.NewFailure("publisher not allowed") + } + header := map[string]string{} + if payload.Request != nil { + for k := range payload.Request.Header { + header[k] = payload.Request.Header.Get(k) + } + } + moduleContext := make(hookstage.ModuleContext) + moduleContext[wurflHeaderCtxKey] = header + result.ModuleContext = moduleContext + + return result, nil +} + +// HandleRawAuctionHook implements hookstage.RawAuctionRequest. +func (m Module) HandleRawAuctionHook( + ctx context.Context, + invocationCtx hookstage.ModuleInvocationContext, + payload hookstage.RawAuctionRequestPayload, +) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) { + result := hookstage.HookResult[hookstage.RawAuctionRequestPayload]{} + + if invocationCtx.ModuleContext == nil { + // The module context has not been initialized in the entrypoint hook. + // This could be due to a not allowed publisher or an error. + // Return the payload as is + return result, hookexecution.NewFailure("module context has not been initialized in the entrypoint hook") + } + + if isWURFLEnrichedRequest(payload) { + return result, nil + } + + rawHeaders, ok := invocationCtx.ModuleContext[wurflHeaderCtxKey].(map[string]string) + if !ok { + return result, hookexecution.NewFailure("invalid module context type") + } + result.ChangeSet.AddMutation(func(payload hookstage.RawAuctionRequestPayload) (hookstage.RawAuctionRequestPayload, error) { + ortb2Device, err := getOrtb2Device(payload) + if err != nil { + return payload, hookexecution.NewFailure("could not get ortb2.Device from payload %s", err) + } + + headers := makeHeaders(ortb2Device, rawHeaders) + + wd, err := m.we.DeviceDetection(headers) + if err != nil { + return payload, hookexecution.NewFailure("could not perform WURFL device detection %s", err) + } + + we := &wurflEnricher{ + WurflData: wd, + ExtCaps: m.extCaps, + } + we.EnrichDevice(&ortb2Device) + + updatedPayload, err := sjson.SetBytes(payload, "device", ortb2Device) + if err != nil { + return payload, hookexecution.NewFailure("could not update ortb2.Device payload %s", err) + } + return updatedPayload, nil + }, + hookstage.MutationUpdate, + "device", + ) + return result, nil +} + +// isPublisherAllowed verifies whether the publisher ID from a request payload is allowed to use this module. +// It checks against a list of authorized IDs, searching for the publisher ID in the site, app, or DOOH fields. +func (m Module) isPublisherAllowed(payload []byte) bool { + if m.allowedPublisherIDs == nil { + return true + } + var publisherID string + jsonparser.EachKey(payload, func(idx int, value []byte, vt jsonparser.ValueType, err error) { + if err != nil { + return + } + if vt != jsonparser.String { + return + } + publisherID = string(value) + }, payloadPublisherIDPaths...) + if publisherID == "" { + return false + } + _, found := m.allowedPublisherIDs[publisherID] + return found +} + +// getOrtb2Device extracts the openrtb2.Device from the bid request body. +func getOrtb2Device(payload []byte) (openrtb2.Device, error) { + device := openrtb2.Device{} + b, t, _, err := jsonparser.Get(payload, "device") + if err != nil { + return device, err + } + if t != jsonparser.Object { + return device, fmt.Errorf("expecting Object, got %s", t) + } + err = jsonutil.Unmarshal(b, &device) + return device, err +} + +// isWURFLEnrichedRequest returns true if the payload request has been already +// enriched with WURFL data like requests from Prebid.js with WURFL RTD module +func isWURFLEnrichedRequest(payload []byte) bool { + _, _, _, err := jsonparser.Get(payload, "device", "ext", ortb2WurflExtKey) + return err == nil +} diff --git a/modules/scientiamobile/wurfl_devicedetection/module_test.go b/modules/scientiamobile/wurfl_devicedetection/module_test.go new file mode 100644 index 0000000000..64aaefe7fd --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/module_test.go @@ -0,0 +1,537 @@ +package wurfl_devicedetection + +import ( + "context" + "errors" + "net/http" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + + "github.com/prebid/prebid-server/v4/hooks/hookstage" + "github.com/stretchr/testify/assert" +) + +func TestHandleEntrypointHook(t *testing.T) { + tests := []struct { + name string + module Module + payload hookstage.EntrypointPayload + expectedError bool + expectedModuleCtx map[string]map[string]string + }{ + { + name: "Publisher allowed with headers", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + Request: &http.Request{ + Header: http.Header{ + "User-Agent": {"Mozilla/5.0"}, + "X-Test": {"HeaderValue"}, + }, + }, + }, + expectedError: false, + expectedModuleCtx: map[string]map[string]string{ + wurflHeaderCtxKey: { + "User-Agent": "Mozilla/5.0", + "X-Test": "HeaderValue", + }, + }, + }, + { + name: "Publisher not allowed", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher":{"id":"pub2"}}}`), + Request: &http.Request{ + Header: http.Header{ + "User-Agent": {"Mozilla/5.0"}, + }, + }, + }, + expectedError: true, + expectedModuleCtx: nil, + }, + { + name: "No publisher ID in payload", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{}`), + Request: &http.Request{ + Header: http.Header{ + "User-Agent": {"Mozilla/5.0"}, + }, + }, + }, + expectedError: true, + expectedModuleCtx: nil, + }, + { + name: "Nil Request, publisher allowed", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + Request: nil, + }, + expectedError: false, + expectedModuleCtx: map[string]map[string]string{ + wurflHeaderCtxKey: {}, + }, + }, + { + name: "Nil allowedPublisherIDs (all publishers allowed)", + module: Module{ + allowedPublisherIDs: nil, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + Request: &http.Request{ + Header: http.Header{ + "X-Custom-Header": {"HeaderValue"}, + }, + }, + }, + expectedError: false, + expectedModuleCtx: map[string]map[string]string{ + wurflHeaderCtxKey: { + "X-Custom-Header": "HeaderValue", + }, + }, + }, + { + name: "Malformed payload", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher": `), + Request: &http.Request{ + Header: http.Header{ + "X-Custom-Header": {"HeaderValue"}, + }, + }, + }, + expectedError: true, + expectedModuleCtx: nil, + }, + { + name: "Empty headers", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: hookstage.EntrypointPayload{ + Body: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + Request: &http.Request{Header: http.Header{}}, + }, + expectedError: false, + expectedModuleCtx: map[string]map[string]string{ + wurflHeaderCtxKey: {}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.module.HandleEntrypointHook(context.Background(), hookstage.ModuleInvocationContext{}, tc.payload) + + if tc.expectedError { + assert.Error(t, err) + assert.Nil(t, result.ModuleContext) + } else { + assert.NoError(t, err) + assert.NotNil(t, result.ModuleContext) + assert.Equal(t, tc.expectedModuleCtx[wurflHeaderCtxKey], result.ModuleContext[wurflHeaderCtxKey]) + } + }) + } +} + +func TestHandleRawAuctionHook(t *testing.T) { + tests := []struct { + name string + module Module + invocationCtx hookstage.ModuleInvocationContext + payload hookstage.RawAuctionRequestPayload + expectedErr bool + mutationErr bool + expectedPayload string + }{ + { + name: "Successful device enrichment without extCaps", + module: Module{ + we: &mockWurflDeviceDetection{ + detectDeviceFunc: func(headers map[string]string) (wurflData, error) { + return wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile", + }, nil + }, + }, + extCaps: false, + }, + invocationCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + wurflHeaderCtxKey: map[string]string{ + "User-Agent": "Mozilla/5.0", + }, + }, + }, + payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), + expectedErr: false, + expectedPayload: `{ + "device": { + "ua": "Mozilla/5.0", + "make": "BrandX", + "model": "ModelY", + "hwv": "ModelY", + "devicetype": 1 + } + }`, + }, + { + name: "Nil module context", + module: Module{ + we: &mockWurflDeviceDetection{ + detectDeviceFunc: func(headers map[string]string) (wurflData, error) { + return wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile", + }, nil + }, + }, + extCaps: false, + }, + invocationCtx: hookstage.ModuleInvocationContext{}, + payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), + expectedErr: true, + expectedPayload: `{"device":{"ua":"Mozilla/5.0"}}`, + }, + { + name: "Successful device enrichment with extCaps", + module: Module{ + we: &mockWurflDeviceDetection{ + detectDeviceFunc: func(headers map[string]string) (wurflData, error) { + return wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile", + }, nil + }, + }, + extCaps: true, + }, + invocationCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + wurflHeaderCtxKey: map[string]string{ + "User-Agent": "Mozilla/5.0", + }, + }, + }, + payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), + expectedErr: false, + expectedPayload: `{ + "device": { + "ua": "Mozilla/5.0", + "make": "BrandX", + "model": "ModelY", + "hwv": "ModelY", + "devicetype": 1, + "ext": { + "wurfl": { + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile" + } + } + } + }`, + }, + { + name: "Successful device enrichment with ext data and with extCaps", + module: Module{ + we: &mockWurflDeviceDetection{ + detectDeviceFunc: func(headers map[string]string) (wurflData, error) { + return wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile", + }, nil + }, + }, + extCaps: true, + }, + invocationCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + wurflHeaderCtxKey: map[string]string{ + "User-Agent": "Mozilla/5.0", + }, + }, + }, + payload: []byte(`{"device":{"ua":"Mozilla/5.0", "ext": {"test": 1}}}`), + expectedErr: false, + expectedPayload: `{ + "device": { + "ua": "Mozilla/5.0", + "make": "BrandX", + "model": "ModelY", + "hwv": "ModelY", + "devicetype": 1, + "ext": { + "test": 1, + "wurfl": { + "brand_name": "BrandX", + "model_name": "ModelY", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + "form_factor": "Other Mobile" + } + } + } + }`, + }, + { + name: "Failed device detection", + module: Module{ + we: &mockWurflDeviceDetection{ + detectDeviceFunc: func(headers map[string]string) (wurflData, error) { + return nil, errors.New("device detection error") + }, + }, + extCaps: false, + }, + invocationCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + wurflHeaderCtxKey: map[string]string{ + "User-Agent": "Mozilla/5.0", + }, + }, + }, + payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), + expectedErr: false, + mutationErr: true, + expectedPayload: `{"device":{"ua":"Mozilla/5.0"}}`, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.module.HandleRawAuctionHook(context.Background(), tc.invocationCtx, tc.payload) + if tc.expectedErr { + assert.Error(t, err) + assert.JSONEq(t, tc.expectedPayload, string(tc.payload)) + return + } + assert.NoError(t, err) + + assert.Equal(t, len(result.ChangeSet.Mutations()), 1) + + assert.Equal(t, result.ChangeSet.Mutations()[0].Type(), hookstage.MutationUpdate) + + mutation := result.ChangeSet.Mutations()[0] + // Apply mutation + mutatedPayload, err := mutation.Apply(tc.payload) + if tc.mutationErr { + assert.Error(t, err) + assert.JSONEq(t, tc.expectedPayload, string(tc.payload)) + return + } + assert.NoError(t, err) + + // Verify the mutated payload + assert.JSONEq(t, tc.expectedPayload, string(mutatedPayload)) + }) + } +} + +// Mock implementation of wurflDeviceDetection +type mockWurflDeviceDetection struct { + detectDeviceFunc func(headers map[string]string) (wurflData, error) +} + +func (m *mockWurflDeviceDetection) DeviceDetection(headers map[string]string) (wurflData, error) { + return m.detectDeviceFunc(headers) +} + +func TestIsPublisherAllowed(t *testing.T) { + tests := []struct { + name string + module Module + payload []byte + expected bool + allowedPublisherIDs map[string]bool + }{ + { + name: "Allowed publisher - site.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + expected: true, + }, + { + name: "Disallowed publisher - site.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: []byte(`{"site":{"publisher":{"id":"pub2"}}}`), + expected: false, + }, + { + name: "Allowed publisher - app.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub3": {}}, + }, + payload: []byte(`{"app":{"publisher":{"id":"pub3"}}}`), + expected: true, + }, + { + name: "Disallowed publisher - app.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub3": {}}, + }, + payload: []byte(`{"app":{"publisher":{"id":"pub4"}}}`), + expected: false, + }, + { + name: "Allowed publisher - dooh.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub5": {}}, + }, + payload: []byte(`{"dooh":{"publisher":{"id":"pub5"}}}`), + expected: true, + }, + { + name: "Disallowed publisher - dooh.publisher.id", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub5": {}}, + }, + payload: []byte(`{"dooh":{"publisher":{"id":"pub6"}}}`), + expected: false, + }, + { + name: "Empty payload - no publisher ID", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: []byte(`{}`), + expected: false, + }, + { + name: "Nil allowedPublisherIDs - all publishers allowed", + module: Module{ + allowedPublisherIDs: nil, + }, + payload: []byte(`{"site":{"publisher":{"id":"pub1"}}}`), + expected: true, + }, + { + name: "Malformed JSON - no publisher ID", + module: Module{ + allowedPublisherIDs: map[string]struct{}{"pub1": {}}, + }, + payload: []byte(`{"site":{"publisher":{}}`), // Missing closing braces + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := tc.module.isPublisherAllowed(tc.payload) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestGetOrtb2Device(t *testing.T) { + tests := []struct { + name string + payload []byte + expectError bool + expected openrtb2.Device + }{ + { + name: "Valid device object", + payload: []byte(`{ + "device": { + "ua": "Mozilla/5.0", + "ip": "192.168.0.1", + "make": "Apple", + "model": "iPhone" + } + }`), + expectError: false, + expected: openrtb2.Device{ + UA: "Mozilla/5.0", + IP: "192.168.0.1", + Make: "Apple", + Model: "iPhone", + }, + }, + { + name: "Missing device field", + payload: []byte(`{}`), + expectError: true, + expected: openrtb2.Device{}, + }, + { + name: "Invalid device type (non-object)", + payload: []byte(`{"device": "string_instead_of_object"}`), + expectError: true, + expected: openrtb2.Device{}, + }, + { + name: "Malformed JSON", + payload: []byte(`{"device": { "ua": "Mozilla/5.0"`), // Missing closing braces + expectError: true, + expected: openrtb2.Device{}, + }, + { + name: "Empty payload", + payload: []byte(``), + expectError: true, + expected: openrtb2.Device{}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + device, err := getOrtb2Device(tc.payload) + + if tc.expectError { + assert.Error(t, err) + assert.Equal(t, tc.expected, device) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expected, device) + } + }) + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/module_wurfl_test.go b/modules/scientiamobile/wurfl_devicedetection/module_wurfl_test.go new file mode 100644 index 0000000000..e89784d52f --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/module_wurfl_test.go @@ -0,0 +1,59 @@ +//go:build wurfl + +package wurfl_devicedetection + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/modules/moduledeps" + "github.com/stretchr/testify/assert" +) + +func TestBuilder(t *testing.T) { + tests := []struct { + name string + configRaw json.RawMessage + expectedErr bool + validate func(t *testing.T, module interface{}) + }{ + { + name: "Valid configuration", + configRaw: json.RawMessage(`{ + "wurfl_snapshot_url": "http://example.com/wurfl-data", + "wurfl_file_path": "/tmp/wurfl.zip", + "allowed_publisher_ids": ["pub1", "pub2"], + "ext_caps": true + }`), + expectedErr: false, + validate: func(t *testing.T, module interface{}) { + m, ok := module.(Module) + assert.True(t, ok, "Module type assertion failed") + assert.Equal(t, map[string]struct{}{"pub1": {}, "pub2": {}}, m.allowedPublisherIDs) + assert.True(t, m.extCaps) + assert.NotNil(t, m.we) + }, + }, + { + name: "Invalid configuration - newConfig fails", + configRaw: json.RawMessage(`{ "wurfl_snapshot_url": "http://example.com/wurfl-data" }`), // Missing required fields + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + module, err := Builder(tc.configRaw, moduledeps.ModuleDeps{}) + + if tc.expectedErr { + assert.Error(t, err) + return + } + + assert.NoError(t, err) + if tc.validate != nil { + tc.validate(t, module) + } + }) + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/sample/pbs_example.json b/modules/scientiamobile/wurfl_devicedetection/sample/pbs_example.json new file mode 100644 index 0000000000..2a0e7b60fc --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/sample/pbs_example.json @@ -0,0 +1,68 @@ +{ + "adapters": [ + { + "appnexus": { + "enabled": true + } + } + ], + "gdpr": { + "enabled": true, + "default_value": 0, + "timeouts_ms": { + "active_vendorlist_fetch": 900000 + } + }, + "hooks": { + "enabled": true, + "modules": { + "scientiamobile": { + "wurfl_devicedetection": { + "enabled": true, + "wurfl_file_path": "/path/to/wurfl.zip", + "wurfl_snapshot_url": "<wurfl_snapshot_url>", + "wurfl_cache_size": 200000, + "allowed_publisher_ids": [ + "1", + "3" + ], + "ext_caps": true + } + } + }, + "host_execution_plan": { + "endpoints": { + "/openrtb2/auction": { + "stages": { + "entrypoint": { + "groups": [ + { + "timeout": 10, + "hook_sequence": [ + { + "module_code": "scientiamobile.wurfl_devicedetection", + "hook_impl_code": "scientiamobile-wurfl_devicedetection-entrypoint-hook" + } + ] + } + ] + }, + "raw_auction_request": { + "groups": [ + { + "timeout": 10, + "hook_sequence": [ + { + "module_code": "scientiamobile.wurfl_devicedetection", + "hook_impl_code": "scientiamobile-wurfl_devicedetection-raw-auction-request-hook" + } + ] + } + ] + } + } + } + } + } + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/sample/request_data.json b/modules/scientiamobile/wurfl_devicedetection/sample/request_data.json new file mode 100644 index 0000000000..42691bbc74 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/sample/request_data.json @@ -0,0 +1,119 @@ +{ + "imp": [ + { + "ext": { + "data": { + "adserver": { + "name": "gam", + "adslot": "test" + }, + "pbadslot": "test", + "gpid": "test" + }, + "gpid": "test", + "prebid": { + "bidder": { + "appnexus": { + "placement_id": 1, + "use_pmt_rule": false + }, + "0test": { + "placement_id": 1 + } + }, + "adunitcode": "25e8ad9f-13a4-4404-ba74-f9eebff0e86c", + "floors": { + "floorMin": 0.01 + } + } + }, + "id": "2529eeea-813e-4da6-838f-f91c28d64867", + "banner": { + "topframe": 1, + "format": [ + { + "w": 728, + "h": 90 + } + ], + "pos": 1 + }, + "bidfloor": 0.01, + "bidfloorcur": "USD" + } + ], + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "1" + }, + "page": "https://www.test.com/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 15; Pixel 9 Pro XL Build/AP3A.241005.015; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 EdgA/124.0.2478.64" + }, + "id": "fc4670ce-4985-4316-a245-b43c885dc37a", + "test": 1, + "cur": [ + "USD" + ], + "source": { + "ext": { + "schain": { + "ver": "1.0", + "complete": 1, + "nodes": [ + { + "asi": "example.com", + "sid": "1234", + "hp": 1 + } + ] + } + } + }, + "ext": { + "prebid": { + "cache": { + "bids": { + "returnCreative": true + }, + "vastxml": { + "returnCreative": true + } + }, + "auctiontimestamp": 1799310801804, + "targeting": { + "includewinners": true, + "includebidderkeys": false + }, + "schains": [ + { + "bidders": [ + "appnexus" + ], + "schain": { + "ver": "1.0", + "complete": 1, + "nodes": [ + { + "asi": "example.com", + "sid": "1234", + "hp": 1 + } + ] + } + } + ], + "floors": { + "enabled": false, + "floorMin": 0.01, + "floorMinCur": "USD" + }, + "createtids": false + } + }, + "user": {}, + "tmax": 2000 +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_data.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_data.go new file mode 100644 index 0000000000..7cc1284407 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_data.go @@ -0,0 +1,86 @@ +package wurfl_devicedetection + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +const ( + wurflID = "wurfl_id" +) + +var ErrWURFLIDNotExist = errors.New("WURFL ID does not exist") + +// declare conformity with json.Marshaler interface +var _ json.Marshaler = wurflData{} + +// wurflData represents the WURFL data +type wurflData map[string]string + +// Bool retrieves a capability value as a bool +func (wd wurflData) Bool(key string) (bool, error) { + val, exists := wd[key] + if !exists { + return false, fmt.Errorf("capability not found: %q", key) + } + result, err := strconv.ParseBool(val) + if err != nil { + return false, fmt.Errorf("could not parse %q to bool for capability %q", val, key) + } + return result, nil +} + +// Int64 retrieves a capability value as an int64 +func (wd wurflData) Int64(key string) (int64, error) { + val, exists := wd[key] + if !exists { + return 0, fmt.Errorf("capability not found: %q", key) + } + result, err := strconv.ParseInt(val, 10, 64) + if err != nil { + return 0, fmt.Errorf("could not parse %q to int64 for capability %q", val, key) + } + return result, nil +} + +// Float64 retrieves a capability value as a float64 +func (wd wurflData) Float64(key string) (float64, error) { + val, exists := wd[key] + if !exists { + return 0.0, fmt.Errorf("capability not found: %q", key) + } + result, err := strconv.ParseFloat(val, 64) + if err != nil { + return 0.0, fmt.Errorf("could not parse %q to float64 for capability %q", val, key) + } + return result, nil +} + +// String retrieves a capability value as a string +func (wd wurflData) String(key string) (string, error) { + val, exists := wd[key] + if !exists { + return "", fmt.Errorf("capability not found: %q", key) + } + return val, nil +} + +// WurflIDToJSON returns a JSON representation of the WURFL ID +func (wd wurflData) WurflIDToJSON() ([]byte, error) { + m := make(map[string]string) + v, ok := wd[wurflID] + if !ok { + return nil, ErrWURFLIDNotExist + } + m[wurflID] = v + return jsonutil.Marshal(m) +} + +// MarshalJSON customizes the JSON marshaling for wurflData +func (wd wurflData) MarshalJSON() ([]byte, error) { + return jsonutil.Marshal(map[string]string(wd)) +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_data_test.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_data_test.go new file mode 100644 index 0000000000..257d5933d9 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_data_test.go @@ -0,0 +1,145 @@ +package wurfl_devicedetection + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWurflData_MarshalJSON(t *testing.T) { + tests := []struct { + name string + data wurflData + expected string + }{ + { + name: "Non-empty wurflData", + data: wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + }, + expected: `{"brand_name":"BrandX","model_name":"ModelY"}`, + }, + { + name: "Empty wurflData", + data: wurflData{}, + expected: `{}`, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.data.MarshalJSON() + assert.NoError(t, err) + assert.JSONEq(t, tc.expected, string(result)) + }) + } +} + +func TestWurflData_SON(t *testing.T) { + tests := []struct { + name string + data wurflData + expected string + expectedErr bool + }{ + { + name: "Non-empty wurflData", + data: wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "wurfl_id": "test", + }, + expected: `{"wurfl_id":"test"}`, + }, + { + name: "Missed WURFL ID", + data: wurflData{}, + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.data.WurflIDToJSON() + if tc.expectedErr { + assert.Error(t, err) + assert.Nil(t, result) + return + } + assert.NoError(t, err) + assert.JSONEq(t, tc.expected, string(result)) + }) + } +} + +func TestWurflData_Bool(t *testing.T) { + data := wurflData{ + "ajax_support_javascript": "true", + "invalid_value": "not_a_bool", + } + + v, err := data.Bool("ajax_support_javascript") + assert.NoError(t, err) + assert.True(t, v) + + v, err = data.Bool("invalid_value") + assert.Error(t, err) + assert.Empty(t, v) + + v, err = data.Bool("non_existent_key") + assert.Error(t, err) + assert.Empty(t, v) +} + +func TestWurflData_Float64(t *testing.T) { + data := wurflData{ + "density_class": "2.5", + "invalid_value": "not_a_number", + } + + v, err := data.Float64("density_class") + assert.NoError(t, err) + assert.Equal(t, 2.5, v) + + v, err = data.Float64("invalid_value") + assert.Empty(t, v) + assert.Error(t, err) + + v, err = data.Float64("non_existent_key") + assert.Empty(t, v) + assert.Error(t, err) +} + +func TestWurflData_Int64(t *testing.T) { + data := wurflData{ + "resolution_height": "1080", + "invalid_value": "not_a_number", + } + + v, err := data.Int64("resolution_height") + assert.NoError(t, err) + assert.Equal(t, int64(1080), v) + + v, err = data.Int64("invalid_value") + assert.Empty(t, v) + assert.Error(t, err) + + v, err = data.Int64("non_existent_key") + assert.Empty(t, v) + assert.Error(t, err) +} + +func TestWurflData_String(t *testing.T) { + data := wurflData{ + "brand_name": "BrandX", + } + + v, err := data.String("brand_name") + assert.NoError(t, err) + assert.Equal(t, "BrandX", v) + + v, err = data.String("non_existent_key") + assert.Empty(t, v) + assert.Error(t, err) +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_engine.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine.go new file mode 100644 index 0000000000..ebcad9c607 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine.go @@ -0,0 +1,145 @@ +//go:build wurfl + +package wurfl_devicedetection + +import ( + "fmt" + "strings" + + wurfl "github.com/WURFL/golang-wurfl" + "github.com/golang/glog" +) + +// declare conformity with wurflDeviceDetection interface +var _ wurflDeviceDetection = (*wurflEngine)(nil) + +// vcaps is the list of WURFL virtual capabilities to request +var vcaps = []string{ + advertisedDeviceOSCapKey, + advertisedDeviceOSVersionCapKey, + completeDeviceNameCapKey, + isFullDesktopCapKey, + isMobileCapKey, + isPhoneCapKey, + formFactorCapKey, + pixelDensityCapKey, +} + +// newWurflEngine creates a new Enricher +func newWurflEngine(c config) (wurflDeviceDetection, error) { + wengine, err := wurfl.Create(c.WURFLFilePath, + nil, + nil, + -1, + wurfl.WurflCacheProviderLru, + c.WURFLEngineCacheSize(), + ) + if err != nil { + return nil, err + } + + caps := wengine.GetAllCaps() + e := &wurflEngine{ + wengine: wengine, + caps: caps, + vcaps: vcaps, + } + + err = e.validate() + if err != nil { + return nil, err + } + + e.startUpdater(c.WURFLSnapshotURL) + + return e, nil +} + +// wurflEngine is the ortb2 enricher powered by WURFL +type wurflEngine struct { + wengine *wurfl.Wurfl + caps []string + vcaps []string +} + +// deviceDetection performs device detection using the WURFL engine. +func (e *wurflEngine) DeviceDetection(headers map[string]string) (wurflData, error) { + wurflDevice, err := e.wengine.LookupWithImportantHeaderMap(headers) + if err != nil { + return nil, err + } + defer wurflDevice.Destroy() + + wurflDeviceID, err := wurflDevice.GetDeviceID() + if err != nil { + return nil, err + } + wurflData, err := wurflDevice.GetStaticCaps(e.caps) + if err != nil { + return nil, err + } + vcaps, err := wurflDevice.GetVirtualCaps(e.vcaps) + if err != nil { + return nil, err + } + for k, v := range vcaps { + wurflData[k] = v + } + wurflData[wurflID] = wurflDeviceID + return wurflData, nil +} + +func (e *wurflEngine) startUpdater(snapshotURL string) { + if snapshotURL == "" { + return + } + + err := e.wengine.SetUpdaterDataURL(snapshotURL) + if err != nil { + glog.Errorf("could not set WURFL Updater Snapshot URL: %s", err.Error()) + return + } + + err = e.wengine.SetUpdaterDataFrequency(wurfl.WurflUpdaterFrequencyDaily) + if err != nil { + glog.Errorf("could not set the WURFL Updater frequency: %s", err.Error()) + return + } + + err = e.wengine.UpdaterStart() + if err != nil { + glog.Errorf("could not start the WURFL Updater: %s", err.Error()) + return + } +} + +// validate checks if the WURFL file has all the required capabilities +func (e *wurflEngine) validate() error { + requiredCaps := []string{ + ajaxSupportJavascriptCapKey, + brandNameCapKey, + densityClassCapKey, + isConnectedTVCapKey, + isConsoleCapKey, + isOTTCapKey, + isTabletCapKey, + modelNameCapKey, + physicalFormFactorCapKey, + resolutionHeightCapKey, + resolutionWidthCapKey, + } + m := map[string]struct{}{} + for _, val := range e.caps { + m[val] = struct{}{} + } + missed := []string{} + for _, val := range requiredCaps { + if _, ok := m[val]; !ok { + missed = append(missed, val) + } + } + if len(missed) > 0 { + return fmt.Errorf("WURFL file is missing the following capabilities: %s", strings.Join(missed, ",")) + } + return nil +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback.go new file mode 100644 index 0000000000..8c83b9f89e --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback.go @@ -0,0 +1,11 @@ +//go:build !wurfl + +package wurfl_devicedetection + +import "errors" + +const wurflBuildTagMissingError = "wurfl module requires the wurfl build tag; build with: go build -tags wurfl" + +func newWurflEngine(_ config) (wurflDeviceDetection, error) { + return nil, errors.New(wurflBuildTagMissingError) +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback_test.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback_test.go new file mode 100644 index 0000000000..de0334fe19 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_engine_fallback_test.go @@ -0,0 +1,14 @@ +//go:build !wurfl + +package wurfl_devicedetection + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewWurflEngineFallbackError(t *testing.T) { + _, err := newWurflEngine(config{}) + assert.EqualError(t, err, wurflBuildTagMissingError) +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher.go new file mode 100644 index 0000000000..a7753bac35 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher.go @@ -0,0 +1,194 @@ +package wurfl_devicedetection + +import ( + "github.com/golang/glog" + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/tidwall/sjson" +) + +const ( + advertisedDeviceOSCapKey = "advertised_device_os" + advertisedDeviceOSVersionCapKey = "advertised_device_os_version" + ajaxSupportJavascriptCapKey = "ajax_support_javascript" + brandNameCapKey = "brand_name" + completeDeviceNameCapKey = "complete_device_name" + densityClassCapKey = "density_class" + formFactorCapKey = "form_factor" + isConsoleCapKey = "is_console" + isConnectedTVCapKey = "is_connected_tv" + isFullDesktopCapKey = "is_full_desktop" + isMobileCapKey = "is_mobile" + isOTTCapKey = "is_ott" + isPhoneCapKey = "is_phone" + isTabletCapKey = "is_tablet" + modelNameCapKey = "model_name" + physicalFormFactorCapKey = "physical_form_factor" + pixelDensityCapKey = "pixel_density" + resolutionHeightCapKey = "resolution_height" + resolutionWidthCapKey = "resolution_width" +) + +const ( + ortb2WurflExtKey = "wurfl" +) + +const ( + outOfHomeDevice = "out_of_home_device" +) + +// WURFL form_factor values +const ( + formFactorDesktop = "Desktop" + formFactorSmartphone = "Smartphone" + formFactorFeaturePhone = "Feature Phone" + formFactorTablet = "Tablet" + formFactorSmartTV = "Smart-TV" + formFactorOtherNonMobile = "Other Non-Mobile" + formFactorOtherMobile = "Other Mobile" +) + +// wurflDeviceDetection wraps the methods for the WURFL device detection +type wurflDeviceDetection interface { + DeviceDetection(headers map[string]string) (wurflData, error) +} + +// wurflEnricher represents the WURFL Enricher for Prebid +type wurflEnricher struct { + // WurflData holds the WURFL data + WurflData wurflData + // extCaps if true will enrich the device.ext field with all WURFL caps + // Default to enrich only with the wurfl_id + ExtCaps bool +} + +// EnrichDevice enriches OpenRTB 2.x device with WURFL data +func (we *wurflEnricher) EnrichDevice(device *openrtb2.Device) { + wd := we.WurflData + if device.Make == "" { + if v, err := wd.String(brandNameCapKey); err == nil { + device.Make = v + } + } + if device.Model == "" { + if v, err := wd.String(modelNameCapKey); err == nil { + device.Model = v + } + } + if device.DeviceType == 0 { + device.DeviceType = we.makeDeviceType() + } + if device.OS == "" { + if v, err := wd.String(advertisedDeviceOSCapKey); err == nil { + device.OS = v + } + } + if device.OSV == "" { + if v, err := wd.String(advertisedDeviceOSVersionCapKey); err == nil { + device.OSV = v + } + } + if device.HWV == "" { + if v, err := wd.String(modelNameCapKey); err == nil { + device.HWV = v + } + } + if device.H == 0 { + if v, err := wd.Int64(resolutionHeightCapKey); err == nil { + device.H = v + } + } + if device.W == 0 { + if v, err := wd.Int64(resolutionWidthCapKey); err == nil { + device.W = v + } + } + if device.PPI == 0 { + if v, err := wd.Int64(pixelDensityCapKey); err == nil { + device.PPI = v + } + } + if device.PxRatio == 0 { + if v, err := wd.Float64(densityClassCapKey); err == nil { + device.PxRatio = v + } + } + if device.JS == nil { + if v, err := wd.Bool(ajaxSupportJavascriptCapKey); err == nil { + var js int8 + if v { + js = 1 + } + device.JS = &js + } + } + + wurflExtData, err := we.wurflExtData() + if err != nil { + glog.Warningf("could not create WURFL ext data: %s", err) + return + } + // merges the WURFL data in device.ext under the wurfl "namespace" + ext, err := sjson.SetRawBytes(device.Ext, ortb2WurflExtKey, wurflExtData) + if err != nil { + glog.Warningf("could not set WURFL ext data: %s", err) + return + } + device.Ext = ext +} + +// wurflExtData returns the WURFL data in JSON format for the device.ext field +func (we *wurflEnricher) wurflExtData() ([]byte, error) { + if we.ExtCaps { + // return all WURFL data + return we.WurflData.MarshalJSON() + } + // return only the WURFL ID + return we.WurflData.WurflIDToJSON() +} + +// makeDeviceType returns an OpenRTB2 DeviceType from WURFL data +// see https://www.scientiamobile.com/how-to-populate-iab-openrtb-device-object/ +func (we *wurflEnricher) makeDeviceType() adcom1.DeviceType { + wd := we.WurflData + unknownDeviceType := adcom1.DeviceType(0) + + // Priority 1: Check is_ott + if isOTT, err := wd.Bool(isOTTCapKey); err == nil && isOTT { + return adcom1.DeviceSetTopBox + } + + // Priority 2: Check is_console + if isConsole, err := wd.Bool(isConsoleCapKey); err == nil && isConsole { + return adcom1.DeviceConnected + } + + // Priority 3: Check physical_form_factor for out_of_home_device + if physicalFormFactor, err := wd.String(physicalFormFactorCapKey); err == nil && physicalFormFactor == outOfHomeDevice { + return adcom1.DeviceOOH + } + + // Priority 4: Check if form_factor exists and switch on its value + formFactor, err := wd.String(formFactorCapKey) + if err != nil { + // form_factor not available, return unknown + return unknownDeviceType + } + + switch formFactor { + case formFactorDesktop: + return adcom1.DevicePC + case formFactorSmartphone, formFactorFeaturePhone: + return adcom1.DevicePhone + case formFactorTablet: + return adcom1.DeviceTablet + case formFactorSmartTV: + return adcom1.DeviceTV + case formFactorOtherNonMobile: + return adcom1.DeviceConnected + case formFactorOtherMobile: + return adcom1.DeviceMobile + default: + return unknownDeviceType + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher_test.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher_test.go new file mode 100644 index 0000000000..5c34017232 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_enricher_test.go @@ -0,0 +1,213 @@ +package wurfl_devicedetection + +import ( + "encoding/json" + "testing" + + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/stretchr/testify/assert" +) + +func TestWurflEnricher_EnrichDevice(t *testing.T) { + data := wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + "advertised_device_os": "Android", + "resolution_height": "1080", + "resolution_width": "1920", + "pixel_density": "300", + "density_class": "2.5", + "ajax_support_javascript": "true", + "is_mobile": "true", + "is_phone": "true", + "is_tablet": "false", + } + + device := &openrtb2.Device{} + + we := &wurflEnricher{ + WurflData: data, + } + we.EnrichDevice(device) + + assert.Equal(t, "BrandX", device.Make) + assert.Equal(t, "ModelY", device.Model) + assert.Equal(t, "Android", device.OS) + assert.Equal(t, int64(1080), device.H) + assert.Equal(t, int64(1920), device.W) + assert.Equal(t, int64(300), device.PPI) + assert.Equal(t, 2.5, device.PxRatio) + assert.NotNil(t, device.JS) + assert.Equal(t, int8(1), *device.JS) + assert.Nil(t, device.Ext) +} + +func TestWurflEnricher_EnrichDeviceExt(t *testing.T) { + tests := []struct { + name string + wurflData wurflData + initialExt json.RawMessage + expectedExt string + expectNoError bool + }{ + { + name: "Add wurfl data to empty device ext", + wurflData: wurflData{ + "brand_name": "BrandX", + "model_name": "ModelY", + }, + initialExt: nil, + expectedExt: `{"wurfl":{"brand_name":"BrandX","model_name":"ModelY"}}`, + expectNoError: true, + }, + { + name: "Merge wurfl data into existing device ext", + wurflData: wurflData{ + "brand_name": "BrandZ", + }, + initialExt: json.RawMessage(`{"existing_key":"existing_value"}`), + expectedExt: `{"existing_key":"existing_value","wurfl":{"brand_name":"BrandZ"}}`, + expectNoError: true, + }, + { + name: "Invalid initial ext JSON", + wurflData: wurflData{ + "brand_name": "BrandX", + }, + initialExt: json.RawMessage(`{"invalid_json":`), // Malformed JSON + expectedExt: `{"invalid_json":`, // Should remain as is + expectNoError: false, + }, + { + name: "Empty wurfl data", + wurflData: wurflData{}, + initialExt: nil, + expectedExt: `{"wurfl":{}}`, + expectNoError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + device := &openrtb2.Device{Ext: tc.initialExt} + + we := &wurflEnricher{ + WurflData: tc.wurflData, + ExtCaps: true, + } + // Call the method being tested + we.EnrichDevice(device) + + // Assert the results + if tc.expectNoError { + assert.JSONEq(t, tc.expectedExt, string(device.Ext)) + } else { + assert.NotEqual(t, tc.expectedExt, string(device.Ext)) + } + }) + } +} + +func TestWurflEnricher_MakeDeviceType(t *testing.T) { + tests := []struct { + name string + data wurflData + expected adcom1.DeviceType + }{ + { + name: "Mobile device - form_factor Other Mobile", + data: wurflData{ + "form_factor": "Other Mobile", + }, + expected: adcom1.DeviceMobile, + }, + { + name: "Smartphone device - form_factor Smartphone", + data: wurflData{ + "form_factor": "Smartphone", + }, + expected: adcom1.DevicePhone, + }, + { + name: "Feature Phone device - form_factor Feature Phone", + data: wurflData{ + "form_factor": "Feature Phone", + }, + expected: adcom1.DevicePhone, + }, + { + name: "Connected TV - form_factor Smart-TV", + data: wurflData{ + "form_factor": "Smart-TV", + }, + expected: adcom1.DeviceTV, + }, + { + name: "Full desktop - form_factor Desktop", + data: wurflData{ + "form_factor": "Desktop", + }, + expected: adcom1.DevicePC, + }, + { + name: "Tablet device - form_factor Tablet", + data: wurflData{ + "form_factor": "Tablet", + }, + expected: adcom1.DeviceTablet, + }, + { + name: "Connected device - form_factor Other Non-Mobile", + data: wurflData{ + "form_factor": "Other Non-Mobile", + }, + expected: adcom1.DeviceConnected, + }, + { + name: "Set-top box (OTT) - is_ott has priority", + data: wurflData{ + "is_ott": "true", + "form_factor": "Desktop", + }, + expected: adcom1.DeviceSetTopBox, + }, + { + name: "Console device - is_console has priority", + data: wurflData{ + "is_console": "true", + "form_factor": "Desktop", + }, + expected: adcom1.DeviceConnected, + }, + { + name: "Out-of-home device - physical_form_factor has priority", + data: wurflData{ + "physical_form_factor": "out_of_home_device", + "form_factor": "Desktop", + }, + expected: adcom1.DeviceOOH, + }, + { + name: "Unknown device type - no form_factor", + data: wurflData{}, + expected: adcom1.DeviceType(0), + }, + { + name: "Unknown device type - invalid form_factor", + data: wurflData{ + "form_factor": "Unknown", + }, + expected: adcom1.DeviceType(0), + }, + } + + for _, tc := range tests { + we := &wurflEnricher{ + WurflData: tc.data, + } + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, we.makeDeviceType()) + }) + } +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_headers.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_headers.go new file mode 100644 index 0000000000..163102b414 --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_headers.go @@ -0,0 +1,104 @@ +package wurfl_devicedetection + +import ( + "fmt" + "strings" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/util/iterutil" +) + +const ( + secCHUA = "Sec-CH-UA" + secCHUAPlatform = "Sec-CH-UA-Platform" + secCHUAPlatformVersion = "Sec-CH-UA-Platform-Version" + secCHUAMobile = "Sec-CH-UA-Mobile" + secCHUAArch = "Sec-CH-UA-Arch" + secCHUAModel = "Sec-CH-UA-Model" + secCHUAFullVersionList = "Sec-CH-UA-Full-Version-List" + userAgent = "User-Agent" +) + +// clientHintEscaper escapes special characters in Client Hint header values per RFC 9651. +// Only backslash and double-quote need escaping. Backslash must be escaped first. +var clientHintEscaper = strings.NewReplacer( + `\`, `\\`, // Must escape backslash FIRST + `"`, `\"`, // Then escape quotes +) + +func makeHeaders(ortb2Device openrtb2.Device, rawHeaders map[string]string) map[string]string { + sua := ortb2Device.SUA + ua := ortb2Device.UA + if ua == "" { + if sua == nil { + return rawHeaders + } + if sua.Browsers == nil { + return rawHeaders + } + } + headers := make(map[string]string) + + if ua != "" { + headers[userAgent] = ua + } + + if sua == nil { + return headers + } + + if sua.Browsers == nil { + return headers + } + + brandList := makeBrandList(sua.Browsers) + headers[secCHUA] = brandList + headers[secCHUAFullVersionList] = brandList + + if sua.Platform != nil { + headers[secCHUAPlatform] = quoteAndEscapeClientHintField(sua.Platform.Brand) + headers[secCHUAPlatformVersion] = quoteAndEscapeClientHintField(strings.Join(sua.Platform.Version, ".")) + } + + if sua.Model != "" { + headers[secCHUAModel] = quoteAndEscapeClientHintField(sua.Model) + } + + if sua.Architecture != "" { + headers[secCHUAArch] = quoteAndEscapeClientHintField(sua.Architecture) + } + + if sua.Mobile != nil { + headers[secCHUAMobile] = fmt.Sprintf("?%d", *sua.Mobile) + } + + return headers +} + +func makeBrandList(brandVersions []openrtb2.BrandVersion) string { + var builder strings.Builder + first := true + for version := range iterutil.SlicePointerValues(brandVersions) { + if version.Brand == "" { + continue + } + if !first { + builder.WriteString(", ") + } + first = false + + brandName := quoteAndEscapeClientHintField(version.Brand) + builder.WriteString(brandName) + builder.WriteString(`;v="`) + builder.WriteString(clientHintEscaper.Replace(strings.Join(version.Version, "."))) + builder.WriteString(`"`) + } + return builder.String() +} + +// quoteAndEscapeClientHintField escapes special characters per RFC 9651 and wraps +// the value in double quotes for use in HTTP Client Hint header values. +// Backslashes and double-quotes are escaped as required by the structured field specification. +func quoteAndEscapeClientHintField(value string) string { + return `"` + clientHintEscaper.Replace(value) + `"` +} diff --git a/modules/scientiamobile/wurfl_devicedetection/wurfl_headers_test.go b/modules/scientiamobile/wurfl_devicedetection/wurfl_headers_test.go new file mode 100644 index 0000000000..36456954ff --- /dev/null +++ b/modules/scientiamobile/wurfl_devicedetection/wurfl_headers_test.go @@ -0,0 +1,171 @@ +package wurfl_devicedetection + +import ( + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/stretchr/testify/assert" +) + +func TestMakeHeaders(t *testing.T) { + tests := []struct { + name string + device openrtb2.Device + rawHeaders map[string]string + expected map[string]string + }{ + { + name: "No SUA and no UA", + device: openrtb2.Device{}, + rawHeaders: map[string]string{"Custom-Header": "Value"}, + expected: map[string]string{"Custom-Header": "Value"}, + }, + { + name: "Only UA", + device: openrtb2.Device{ + UA: "Mozilla/5.0", + }, + rawHeaders: map[string]string{}, + expected: map[string]string{"User-Agent": "Mozilla/5.0"}, + }, + { + name: "UA and SUA without Browsers", + device: openrtb2.Device{ + UA: "Mozilla/5.0", + SUA: &openrtb2.UserAgent{ + Platform: &openrtb2.BrandVersion{ + Brand: "Android", + Version: []string{"12"}, + }, + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{"User-Agent": "Mozilla/5.0"}, + }, + { + name: "No UA and SUA without Browsers", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Platform: &openrtb2.BrandVersion{ + Brand: "Android", + Version: []string{"12"}, + }, + }, + }, + rawHeaders: map[string]string{"User-Agent": "Mozilla/5.0"}, + expected: map[string]string{"User-Agent": "Mozilla/5.0"}, + }, + { + name: "SUA with browsers and platform", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Browsers: []openrtb2.BrandVersion{ + {Brand: "Google Chrome", Version: []string{"114", "0", "5735"}}, + }, + Platform: &openrtb2.BrandVersion{ + Brand: "Android", + Version: []string{"12"}, + }, + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{ + "Sec-CH-UA": `"Google Chrome";v="114.0.5735"`, + "Sec-CH-UA-Full-Version-List": `"Google Chrome";v="114.0.5735"`, + "Sec-CH-UA-Platform": `"Android"`, + "Sec-CH-UA-Platform-Version": `"12"`, + }, + }, + { + name: "SUA with mobile and model", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Browsers: []openrtb2.BrandVersion{ + {Brand: "Google Chrome", Version: []string{"114", "0", "5735"}}, + }, + Mobile: func(i int8) *int8 { return &i }(1), + Model: "Pixel 6", + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{ + "Sec-CH-UA": `"Google Chrome";v="114.0.5735"`, + "Sec-CH-UA-Full-Version-List": `"Google Chrome";v="114.0.5735"`, + "Sec-CH-UA-Mobile": `?1`, + "Sec-CH-UA-Model": `"Pixel 6"`, + }, + }, + { + name: "SUA with multiple browsers brand", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Browsers: []openrtb2.BrandVersion{ + {Brand: "Chromium", Version: []string{"114"}}, + {Brand: "Google Chrome", Version: []string{"114", "0", "5735"}}, + {Brand: " Not A;Brand", Version: []string{"99"}}, + }, + Platform: &openrtb2.BrandVersion{ + Brand: "Windows", + Version: []string{"10", "0", "0"}, + }, + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{ + "Sec-CH-UA": `"Chromium";v="114", "Google Chrome";v="114.0.5735", " Not A;Brand";v="99"`, + "Sec-CH-UA-Full-Version-List": `"Chromium";v="114", "Google Chrome";v="114.0.5735", " Not A;Brand";v="99"`, + "Sec-CH-UA-Platform": `"Windows"`, + "Sec-CH-UA-Platform-Version": `"10.0.0"`, + }, + }, + { + name: "SUA with special characters in version strings (RFC 9651)", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Browsers: []openrtb2.BrandVersion{ + {Brand: "Chrome", Version: []string{`1", "Injected";v="99`}}, + {Brand: "Brand", Version: []string{`1\2`}}, + }, + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{ + "Sec-CH-UA": `"Chrome";v="1\", \"Injected\";v=\"99", "Brand";v="1\\2"`, + "Sec-CH-UA-Full-Version-List": `"Chrome";v="1\", \"Injected\";v=\"99", "Brand";v="1\\2"`, + }, + }, + { + name: "SUA with special characters requiring escaping (RFC 9651)", + device: openrtb2.Device{ + SUA: &openrtb2.UserAgent{ + Browsers: []openrtb2.BrandVersion{ + {Brand: `Test"Brand`, Version: []string{"1", "0"}}, + {Brand: `Test\Brand`, Version: []string{"2", "0"}}, + }, + Platform: &openrtb2.BrandVersion{ + Brand: `OS"Name`, + Version: []string{"1"}, + }, + Model: `Device"Model\Name`, + Architecture: `arch\test`, + }, + }, + rawHeaders: map[string]string{}, + expected: map[string]string{ + "Sec-CH-UA": `"Test\"Brand";v="1.0", "Test\\Brand";v="2.0"`, + "Sec-CH-UA-Full-Version-List": `"Test\"Brand";v="1.0", "Test\\Brand";v="2.0"`, + "Sec-CH-UA-Platform": `"OS\"Name"`, + "Sec-CH-UA-Platform-Version": `"1"`, + "Sec-CH-UA-Model": `"Device\"Model\\Name"`, + "Sec-CH-UA-Arch": `"arch\\test"`, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := makeHeaders(test.device, test.rawHeaders) + assert.Equal(t, test.expected, result) + }) + } +} From d7f8515b86258688304b0d9b6668c6a0e258bc9e Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:05:40 +0300 Subject: [PATCH 202/272] New Adapter: AppMonstaMedia (#4727) --- static/bidder-info/appMonstaMedia.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 static/bidder-info/appMonstaMedia.yaml diff --git a/static/bidder-info/appMonstaMedia.yaml b/static/bidder-info/appMonstaMedia.yaml new file mode 100644 index 0000000000..705140a525 --- /dev/null +++ b/static/bidder-info/appMonstaMedia.yaml @@ -0,0 +1,5 @@ +aliasOf: "teqblaze" +endpoint: "https://ssp-us.appmonsta.ai/pserver" +gvlVendorID: 1283 +maintainer: + email: "media.support@appmonsta.ai" From e29653095dfd82f209e6c1f921ccfd152c8351d4 Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Fri, 1 May 2026 21:10:17 +0530 Subject: [PATCH 203/272] Insticator: Move DSP seat from TypedBid to Meta to prevent bid rejection (#4726) --- adapters/insticator/insticator.go | 6 ++--- .../insticatortest/exemplary/app-banner.json | 25 +++++++++++++------ .../insticatortest/exemplary/app-video.json | 25 +++++++++++++------ .../exemplary/multi-format.json | 5 ++-- .../insticatortest/exemplary/multi-imps.json | 14 ++++------- .../insticatortest/exemplary/site-banner.json | 25 +++++++++++++------ .../insticatortest/exemplary/site-video.json | 25 +++++++++++++------ .../supplemental/app-pubid-absent.json | 5 ++-- .../supplemental/currency-conversion.json | 5 ++-- .../supplemental/device-validation.json | 5 ++-- .../multi-imp-mixed-validation.json | 5 ++-- .../supplemental/site-pubid-absent.json | 5 ++-- 12 files changed, 88 insertions(+), 62 deletions(-) diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index 38d25c41f1..2d0014c2c5 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -240,9 +240,8 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R b := &adapters.TypedBid{ Bid: &seatBid.Bid[i], BidType: bidType, - BidMeta: getBidMeta(bid, bidType), + BidMeta: getBidMeta(bid, bidType, seatBid.Seat), BidVideo: getBidVideo(bid, bidType), - Seat: openrtb_ext.BidderName(seatBid.Seat), } bidResponse.Bids = append(bidResponse.Bids, b) } @@ -251,9 +250,10 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R } // getBidMeta extracts metadata from the bid for brand safety and reporting -func getBidMeta(bid *openrtb2.Bid, bidType openrtb_ext.BidType) *openrtb_ext.ExtBidPrebidMeta { +func getBidMeta(bid *openrtb2.Bid, bidType openrtb_ext.BidType, seat string) *openrtb_ext.ExtBidPrebidMeta { meta := &openrtb_ext.ExtBidPrebidMeta{ MediaType: string(bidType), + Seat: seat, } if len(bid.ADomain) > 0 { diff --git a/adapters/insticator/insticatortest/exemplary/app-banner.json b/adapters/insticator/insticatortest/exemplary/app-banner.json index 4b32c066ad..443dde561d 100644 --- a/adapters/insticator/insticatortest/exemplary/app-banner.json +++ b/adapters/insticator/insticatortest/exemplary/app-banner.json @@ -92,8 +92,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1" + ], "crid": "crid_10", "h": 90, "w": 728, @@ -122,8 +126,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1" + ], "crid": "crid_10", "w": 728, "h": 90, @@ -135,14 +143,15 @@ } }, "BidMeta": { - "advertiserDomains": ["insticator.com"], + "advertiserDomains": [ + "insticator.com" + ], "mediaType": "banner", "primaryCatId": "IAB1" }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/exemplary/app-video.json b/adapters/insticator/insticatortest/exemplary/app-video.json index 1002fe9a0c..6173802b15 100644 --- a/adapters/insticator/insticatortest/exemplary/app-video.json +++ b/adapters/insticator/insticatortest/exemplary/app-video.json @@ -127,8 +127,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1-1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1-1" + ], "dur": 30, "mtype": 2, "crid": "crid_10", @@ -158,8 +162,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1-1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1-1" + ], "dur": 30, "crid": "crid_10", "w": 728, @@ -172,7 +180,9 @@ } }, "BidMeta": { - "advertiserDomains": ["insticator.com"], + "advertiserDomains": [ + "insticator.com" + ], "mediaType": "video", "primaryCatId": "IAB1-1" }, @@ -180,10 +190,9 @@ "duration": 30, "primary_category": "IAB1-1" }, - "type": "video", - "seat": "insticator" + "type": "video" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/exemplary/multi-format.json b/adapters/insticator/insticatortest/exemplary/multi-format.json index 3013569713..2efb075a39 100644 --- a/adapters/insticator/insticatortest/exemplary/multi-format.json +++ b/adapters/insticator/insticatortest/exemplary/multi-format.json @@ -138,10 +138,9 @@ "w": 728, "h": 90 }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/exemplary/multi-imps.json b/adapters/insticator/insticatortest/exemplary/multi-imps.json index 5d5531b73e..794c34bfbb 100644 --- a/adapters/insticator/insticatortest/exemplary/multi-imps.json +++ b/adapters/insticator/insticatortest/exemplary/multi-imps.json @@ -308,8 +308,7 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" }, { "bid": { @@ -326,8 +325,7 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" }, { "bid": { @@ -344,8 +342,7 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] }, @@ -367,10 +364,9 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/exemplary/site-banner.json b/adapters/insticator/insticatortest/exemplary/site-banner.json index da7a463ce0..ada1c6c7c0 100644 --- a/adapters/insticator/insticatortest/exemplary/site-banner.json +++ b/adapters/insticator/insticatortest/exemplary/site-banner.json @@ -106,8 +106,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1" + ], "crid": "crid_10", "h": 90, "w": 728, @@ -136,8 +140,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1" + ], "crid": "crid_10", "w": 728, "h": 90, @@ -149,14 +157,15 @@ } }, "BidMeta": { - "advertiserDomains": ["insticator.com"], + "advertiserDomains": [ + "insticator.com" + ], "mediaType": "banner", "primaryCatId": "IAB1" }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/exemplary/site-video.json b/adapters/insticator/insticatortest/exemplary/site-video.json index dc220773f3..0e7b404ba6 100644 --- a/adapters/insticator/insticatortest/exemplary/site-video.json +++ b/adapters/insticator/insticatortest/exemplary/site-video.json @@ -100,8 +100,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1-1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1-1" + ], "dur": 30, "mtype": 2, "crid": "crid_10", @@ -131,8 +135,12 @@ "impid": "test-imp-id", "price": 0.5, "adm": "some-test-vast-ad", - "adomain": ["insticator.com"], - "cat": ["IAB1-1"], + "adomain": [ + "insticator.com" + ], + "cat": [ + "IAB1-1" + ], "dur": 30, "crid": "crid_10", "w": 728, @@ -145,7 +153,9 @@ } }, "BidMeta": { - "advertiserDomains": ["insticator.com"], + "advertiserDomains": [ + "insticator.com" + ], "mediaType": "video", "primaryCatId": "IAB1-1" }, @@ -153,10 +163,9 @@ "duration": 30, "primary_category": "IAB1-1" }, - "type": "video", - "seat": "insticator" + "type": "video" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json b/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json index 8d52f59282..5efc22fa3c 100644 --- a/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json +++ b/adapters/insticator/insticatortest/supplemental/app-pubid-absent.json @@ -123,10 +123,9 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/supplemental/currency-conversion.json b/adapters/insticator/insticatortest/supplemental/currency-conversion.json index 61a6fa290d..a067eac721 100644 --- a/adapters/insticator/insticatortest/supplemental/currency-conversion.json +++ b/adapters/insticator/insticatortest/supplemental/currency-conversion.json @@ -144,10 +144,9 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/supplemental/device-validation.json b/adapters/insticator/insticatortest/supplemental/device-validation.json index 07a243f88b..b6901f9177 100644 --- a/adapters/insticator/insticatortest/supplemental/device-validation.json +++ b/adapters/insticator/insticatortest/supplemental/device-validation.json @@ -160,10 +160,9 @@ } } }, - "type": "video", - "seat": "insticator" + "type": "video" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json index d98a7eebaf..8ea638fcee 100644 --- a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json +++ b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json @@ -171,10 +171,9 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} diff --git a/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json b/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json index 74782b966e..7b2b3c5e6e 100644 --- a/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json +++ b/adapters/insticator/insticatortest/supplemental/site-pubid-absent.json @@ -123,10 +123,9 @@ } } }, - "type": "banner", - "seat": "insticator" + "type": "banner" } ] } ] -} \ No newline at end of file +} From b7a34426f7f8af7d40c315fca5eb7ef5c912c992 Mon Sep 17 00:00:00 2001 From: Ankit Karwa <37686606+karwaankit32@users.noreply.github.com> Date: Fri, 1 May 2026 21:19:16 +0530 Subject: [PATCH 204/272] Upgrade jsonparser from v1.1.1 to v1.1.2 (#4736) Co-authored-by: Ankit Karwa <ankitkarwa@microsoft.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 998750a0ab..f227b9b90c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/alitto/pond v1.8.3 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/benbjohnson/clock v1.3.0 - github.com/buger/jsonparser v1.1.1 + github.com/buger/jsonparser v1.1.2 github.com/chasex/glog v0.0.0-20160217080310-c62392af379c github.com/coocood/freecache v1.2.1 github.com/docker/go-units v0.4.0 diff --git a/go.sum b/go.sum index 2d03cb08c4..6886cbb7b6 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= From 2fae16f31693452b62dd2a0924b78e71bbec43ec Mon Sep 17 00:00:00 2001 From: prebid-reklamup <prebid@reklamup.com> Date: Fri, 1 May 2026 21:27:23 +0300 Subject: [PATCH 205/272] New Adapter: ReklamUp (#4711) --- static/bidder-info/reklamup.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 static/bidder-info/reklamup.yaml diff --git a/static/bidder-info/reklamup.yaml b/static/bidder-info/reklamup.yaml new file mode 100644 index 0000000000..c754ee2d6f --- /dev/null +++ b/static/bidder-info/reklamup.yaml @@ -0,0 +1,22 @@ +aliasOf: "teqblaze" +endpoint: "https://node.reklamup.com/pserver" +maintainer: + email: "support@reklamup.com" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://usersync.reklamup.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://usersync.reklamup.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From c472bd0bc330038cc2dda9c6f61993bf433b1a70 Mon Sep 17 00:00:00 2001 From: quietPusher <129727954+quietPusher@users.noreply.github.com> Date: Wed, 6 May 2026 04:16:54 +0200 Subject: [PATCH 206/272] New Adapter: 9dotsmedialtd - Limelight Alias (#4281) --- static/bidder-info/9dotsmedialtd.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/9dotsmedialtd.yaml diff --git a/static/bidder-info/9dotsmedialtd.yaml b/static/bidder-info/9dotsmedialtd.yaml new file mode 100644 index 0000000000..ad9e7b3f07 --- /dev/null +++ b/static/bidder-info/9dotsmedialtd.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-dot-pbs.ortb.net/openrtb/{{.PublisherID}}" +aliasOf: "limelightDigital" From 843e62fd806d2741d06f35bc66e4d1eaf4633cd0 Mon Sep 17 00:00:00 2001 From: t-sormonte <t.sormonte@sparteo.com> Date: Wed, 6 May 2026 05:23:14 +0200 Subject: [PATCH 207/272] Sparteo: Add required query params to adapter endpoint (#4556) --- adapters/sparteo/sparteo.go | 272 +++++-- adapters/sparteo/sparteo_test.go | 738 +++++++++++++++++- .../sparteotest/exemplary/banner-app.json | 242 ++++++ .../sparteo/sparteotest/exemplary/banner.json | 22 +- .../sparteo/sparteotest/exemplary/native.json | 22 +- .../sparteo/sparteotest/exemplary/video.json | 22 +- .../supplemental/filter-empty-seat-bids.json | 19 +- .../supplemental/filter-invalid-bid-type.json | 19 +- .../supplemental/filter-no-seat-bids.json | 19 +- .../supplemental/invalid-bidder-ext.json | 61 -- .../supplemental/invalid-json-response.json | 19 +- .../supplemental/invalid-publisher-ext.json | 18 +- .../sparteotest/supplemental/status_204.json | 19 +- .../sparteotest/supplemental/status_400.json | 19 +- .../sparteotest/supplemental/status_500.json | 19 +- macros/macros.go | 4 + static/bidder-info/sparteo.yaml | 2 +- 17 files changed, 1347 insertions(+), 189 deletions(-) create mode 100644 adapters/sparteo/sparteotest/exemplary/banner-app.json delete mode 100644 adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json diff --git a/adapters/sparteo/sparteo.go b/adapters/sparteo/sparteo.go index 0653e2c4d7..0a8f0fb286 100644 --- a/adapters/sparteo/sparteo.go +++ b/adapters/sparteo/sparteo.go @@ -3,6 +3,8 @@ package sparteo import ( "fmt" "net/http" + "net/url" + "strings" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v4/adapters" @@ -10,22 +12,24 @@ import ( "github.com/prebid/prebid-server/v4/errortypes" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" ) type adapter struct { - endpoint string - bidderName string + endpoint string } type extBidWrapper struct { Prebid openrtb_ext.ExtBidPrebid `json:"prebid"` } +const unknownValue = "unknown" + func Builder(bidderName openrtb_ext.BidderName, cfg config.Adapter, server config.Server) (adapters.Bidder, error) { - return &adapter{ - endpoint: cfg.Endpoint, - bidderName: string(bidderName), - }, nil + bidder := &adapter{ + endpoint: cfg.Endpoint, + } + return bidder, nil } func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpSparteo, error) { @@ -47,6 +51,7 @@ func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpSparteo, error) { func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { request := *req + var errs []error request.Imp = make([]openrtb2.Imp, len(req.Imp)) copy(request.Imp, req.Imp) @@ -54,25 +59,53 @@ func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.Extra if req.Site != nil { siteCopy := *req.Site request.Site = &siteCopy + if req.Site.Publisher != nil { + pubCopy := *req.Site.Publisher + request.Site.Publisher = &pubCopy + } } - - if req.Site != nil && req.Site.Publisher != nil { - publisherCopy := *req.Site.Publisher - request.Site.Publisher = &publisherCopy + if req.App != nil { + appCopy := *req.App + request.App = &appCopy + if req.App.Publisher != nil { + pubCopy := *req.App.Publisher + request.App.Publisher = &pubCopy + } } - var errs []error - var siteNetworkId string + var siteDomain, appDomain, bundle string + if request.Site != nil { + if sd := resolveSiteDomain(request.Site); sd != nil { + siteDomain = *sd + if siteDomain == unknownValue { + errs = append(errs, &errortypes.BadInput{ + Message: "Domain not found. Missing the site.domain or the site.page field", + }) + } + } + } else if request.App != nil { + if ad := resolveAppDomain(request.App); ad != nil { + appDomain = *ad + } + if b := resolveBundle(request.App); b != nil { + bundle = *b + if bundle == unknownValue { + errs = append(errs, &errortypes.BadInput{ + Message: "Bundle not found. Missing the app.bundle field.", + }) + } + } + } + var networkID string for i, imp := range request.Imp { extImpSparteo, err := parseExt(&imp) if err != nil { errs = append(errs, err) continue } - - if siteNetworkId == "" && extImpSparteo.NetworkId != "" { - siteNetworkId = extImpSparteo.NetworkId + if networkID == "" && extImpSparteo.NetworkId != "" { + networkID = extImpSparteo.NetworkId } var extMap map[string]interface{} @@ -93,12 +126,10 @@ func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.Extra sparteoMap["params"] = paramsMap } - bidderObj, ok := extMap["bidder"].(map[string]interface{}) - if ok { + if bidderObj, ok := extMap["bidder"].(map[string]interface{}); ok { delete(extMap, "bidder") - - for key, value := range bidderObj { - paramsMap[key] = value + for k, v := range bidderObj { + paramsMap[k] = v } } @@ -107,40 +138,32 @@ func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.Extra errs = append(errs, fmt.Errorf("ignoring imp id=%s, error while marshaling updated ext, err: %s", imp.ID, err)) continue } - request.Imp[i].Ext = updatedExt } - if request.Site != nil && request.Site.Publisher != nil && siteNetworkId != "" { - var pubExt map[string]interface{} - if request.Site.Publisher.Ext != nil { - if err := jsonutil.Unmarshal(request.Site.Publisher.Ext, &pubExt); err != nil { - pubExt = make(map[string]interface{}) - } - } else { - pubExt = make(map[string]interface{}) - } - - var paramsMap map[string]interface{} - if raw, ok := pubExt["params"]; ok { - if paramsMap, ok = raw.(map[string]interface{}); !ok { - paramsMap = make(map[string]interface{}) - } - } else { - paramsMap = make(map[string]interface{}) - } - - paramsMap["networkId"] = siteNetworkId - pubExt["params"] = paramsMap + var pub *openrtb2.Publisher + var pubExt string + + if request.Site != nil { + pub = ensurePublisher(request.Site.Publisher) + request.Site.Publisher = pub + pubExt = "site.publisher.ext" + } else if request.App != nil { + pub = ensurePublisher(request.App.Publisher) + request.App.Publisher = pub + pubExt = "app.publisher.ext" + } else { + request.Site = &openrtb2.Site{} + pub = ensurePublisher(request.Site.Publisher) + request.Site.Publisher = pub + pubExt = "site.publisher.ext" + } - updatedPubExt, err := jsonutil.Marshal(pubExt) - if err != nil { - errs = append(errs, &errortypes.BadInput{ - Message: fmt.Sprintf("Error marshaling site.publisher.ext: %s", err), - }) - } else { - request.Site.Publisher.Ext = jsonutil.RawMessage(updatedPubExt) - } + ext, err := updatePublisherExtension(&pub.Ext, networkID, pubExt) + if err != nil { + errs = append(errs, err) + } else { + pub.Ext = ext } body, err := jsonutil.Marshal(request) @@ -149,9 +172,14 @@ func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.Extra return nil, errs } + uri, err := a.buildEndpointURL(networkID, siteDomain, appDomain, bundle) + if err != nil { + return nil, []error{err} + } + requestData := &adapters.RequestData{ Method: http.MethodPost, - Uri: a.endpoint, + Uri: uri, Body: body, ImpIDs: openrtb_ext.GetImpIDs(request.Imp), Headers: http.Header{ @@ -162,6 +190,148 @@ func (a *adapter) MakeRequests(req *openrtb2.BidRequest, reqInfo *adapters.Extra return []*adapters.RequestData{requestData}, errs } +func normalizeHostname(host string) string { + host = strings.TrimSpace(host) + if host == "" { + return "" + } + + u, err := url.Parse(host) + if err != nil || u.Hostname() == "" { + if i := strings.Index(host, ":"); i >= 0 { + host = host[:i] + } else if i := strings.Index(host, "/"); i >= 0 { + host = host[:i] + } + } else { + host = u.Hostname() + } + + host = strings.ToLower(host) + host = strings.TrimSuffix(host, ".") + host = strings.TrimPrefix(host, "www.") + + if host == "null" { + return "" + } + return host +} + +func resolveSiteDomain(site *openrtb2.Site) *string { + if site != nil { + if d := normalizeHostname(site.Domain); d != "" { + return ptrutil.ToPtr(d) + } + if fromPage := normalizeHostname(site.Page); fromPage != "" { + return ptrutil.ToPtr(fromPage) + } + return ptrutil.ToPtr(unknownValue) + } + return nil +} + +func resolveAppDomain(app *openrtb2.App) *string { + if app != nil { + if d := normalizeHostname(app.Domain); d != "" { + return ptrutil.ToPtr(d) + } + return ptrutil.ToPtr(unknownValue) + } + return nil +} + +func resolveBundle(app *openrtb2.App) *string { + if app == nil { + return nil + } + + raw := app.Bundle + if strings.TrimSpace(raw) == "" { + return ptrutil.ToPtr(unknownValue) + } + + b := strings.TrimSpace(raw) + if strings.EqualFold(b, "null") { + return ptrutil.ToPtr(unknownValue) + } + + return ptrutil.ToPtr(b) +} + +func ensurePublisher(p *openrtb2.Publisher) *openrtb2.Publisher { + if p == nil { + p = &openrtb2.Publisher{} + } + if p.Ext == nil { + p.Ext = jsonutil.RawMessage("{}") + } + + return p +} + +func updatePublisherExtension(targetExt *jsonutil.RawMessage, networkID, fieldPath string) ([]byte, error) { + var pubExt map[string]interface{} + if err := jsonutil.Unmarshal(*targetExt, &pubExt); err != nil { + pubExt = make(map[string]interface{}) + } + + params, ok := pubExt["params"].(map[string]interface{}) + if !ok { + params = make(map[string]interface{}) + pubExt["params"] = params + } + params["networkId"] = networkID + + updated, err := jsonutil.Marshal(pubExt) + if err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Error marshaling %s: %s", fieldPath, err), + } + } + return updated, nil +} + +func (a *adapter) buildEndpointURL(networkId string, siteDomain string, appDomain string, bundle string) (string, error) { + parsed, err := url.Parse(a.endpoint) + if err != nil { + return "", fmt.Errorf("invalid endpoint URL %q: %w", a.endpoint, err) + } + + hasSite := siteDomain != "" + hasAppOrBundle := appDomain != "" || bundle != "" + + var b strings.Builder + + b.WriteString("network_id=") + b.WriteString(url.QueryEscape(networkId)) + + if hasSite { + v := siteDomain + if v == "" { + v = unknownValue + } + b.WriteString("&site_domain=") + b.WriteString(url.QueryEscape(v)) + } else if hasAppOrBundle { + ad := appDomain + if ad == "" { + ad = unknownValue + } + bd := bundle + if bd == "" { + bd = unknownValue + } + + b.WriteString("&app_domain=") + b.WriteString(url.QueryEscape(ad)) + b.WriteString("&bundle=") + b.WriteString(url.QueryEscape(bd)) + } + + parsed.RawQuery = b.String() + return parsed.String(), nil +} + func (a *adapter) MakeBids(req *openrtb2.BidRequest, reqData *adapters.RequestData, respData *adapters.ResponseData) (*adapters.BidderResponse, []error) { if adapters.IsResponseStatusCodeNoContent(respData) { return nil, nil diff --git a/adapters/sparteo/sparteo_test.go b/adapters/sparteo/sparteo_test.go index 8e9524dabd..8157c89815 100644 --- a/adapters/sparteo/sparteo_test.go +++ b/adapters/sparteo/sparteo_test.go @@ -2,30 +2,29 @@ package sparteo import ( "encoding/json" + "errors" "testing" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" "github.com/prebid/prebid-server/v4/adapters/adapterstest" "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// TestBuilder verifies that the Builder function correctly creates a bidder instance. -// It checks for errors, ensures the returned bidder is not nil, and confirms that the endpoint -// in the adapter is set according to the configuration. +// TestBuilder verifies that the Builder function correctly creates a bidder instance +// and that the endpoint template renders fields using the new macros. func TestBuilder(t *testing.T) { - cfg := config.Adapter{Endpoint: "https://bid-test.sparteo.com/s2s-auction"} - bidder, err := Builder(openrtb_ext.BidderSparteo, cfg, config.Server{GvlID: 1028}) - - require.NoError(t, err, "Builder returned an error") - assert.NotNil(t, bidder, "Bidder is nil") - - sparteoAdapter, ok := bidder.(*adapter) - require.True(t, ok, "Expected *adapter, got %T", bidder) - - assert.Equal(t, "https://bid-test.sparteo.com/s2s-auction", sparteoAdapter.endpoint, "Endpoint is not correctly set") + cfg := config.Adapter{ + Endpoint: "https://bid-test.sparteo.com/s2s-auction", + } + bidder, err := Builder(openrtb_ext.BidderSparteo, cfg, config.Server{}) + if assert.NoError(t, err) { + assert.NotNil(t, bidder) + } } // TestJsonSamples runs JSON sample tests using the shared adapterstest framework. @@ -73,3 +72,716 @@ func TestGetMediaType_NilExt(t *testing.T) { assert.Error(t, err, "Expected error for nil extension") assert.Equal(t, openrtb_ext.BidType(""), result, "Expected empty result for nil extension") } + +// TestMakeRequests_ResolvesQueryParams verifies that the adapter correctly resolves macros in the endpoint URL for Site traffic. +func TestMakeRequests_ResolvesQueryParams(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{ + Endpoint: endpoint, + }, config.Server{GvlID: 1028}) + require.NoError(t, err, "Builder returned an error") + + in := &openrtb2.BidRequest{ + ID: "req-qp-1", + Site: &openrtb2.Site{ + Domain: "dev.sparteo.com", + }, + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`), + }, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1, "Expected exactly one outgoing request") + assert.Empty(t, errs, "Unexpected adapter errors") + + expectedURI := "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=dev.sparteo.com" + assert.Equal(t, expectedURI, reqs[0].Uri) +} + +// TestMakeRequests_AppBundleMacro verifies that the adapter correctly resolves app_domain and bundle for App traffic. +func TestMakeRequests_AppBundleMacro(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-app-bundle-1", + App: &openrtb2.App{ + Domain: "dev.sparteo.com", + Bundle: "com.sparteo.app", + Publisher: &openrtb2.Publisher{ + ID: "sparteo", + }, + }, + Imp: []openrtb2.Imp{{ + ID: "imp-1", + Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`), + }}, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + assert.Empty(t, errs) + + expected := "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&app_domain=dev.sparteo.com&bundle=com.sparteo.app" + assert.Equal(t, expected, reqs[0].Uri, "endpoint should include app_domain and bundle for App traffic") +} + +// TestMakeRequests_AppBundleMissing_AppendsUnknown verifies that when app.bundle is empty or missing we send bundle=unknown (and warn). +func TestMakeRequests_AppBundleMissing_AppendsUnknown(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-app-nobundle-1", + App: &openrtb2.App{ + Domain: "dev.sparteo.com", + Publisher: &openrtb2.Publisher{ID: "sparteo"}, + }, + Imp: []openrtb2.Imp{{ + ID: "imp-1", + Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`), + }}, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Len(t, errs, 1) + + expected := "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&app_domain=dev.sparteo.com&bundle=unknown" + assert.Equal(t, expected, reqs[0].Uri, "endpoint should contain bundle=unknown when app.bundle is empty") +} + +// TestMakeRequests_SiteDomain verifies that the adapter uses site.Domain and does not include app fields for Site traffic. +func TestMakeRequests_SiteDomain(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{ + Endpoint: endpoint, + }, config.Server{GvlID: 1028}) + require.NoError(t, err, "Builder returned an error") + + in := &openrtb2.BidRequest{ + ID: "req-fallback-1", + Site: &openrtb2.Site{ + Domain: "dev.sparteo.com", + }, + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`), + }, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1, "Expected exactly one outgoing request") + assert.Empty(t, errs, "Unexpected adapter errors") + + expectedURI := "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=dev.sparteo.com" + assert.Equal(t, expectedURI, reqs[0].Uri) +} + +// TestMakeRequests_DomainPrecedence_SiteDomainWins verifies that Site wins over App when both exist. +func TestMakeRequests_DomainPrecedence_SiteDomainWins(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-domain-1", + Site: &openrtb2.Site{ + Domain: "site.sparteo.com", + Publisher: &openrtb2.Publisher{ + Domain: "site-pub.sparteo.com", + }, + }, + App: &openrtb2.App{ + Domain: "app.sparteo.com", + Publisher: &openrtb2.Publisher{ + Domain: "app-pub.should-not-be-used", + }, + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=site.sparteo.com", + reqs[0].Uri, + ) +} + +// TestMakeRequests_SitePresentWithEmptyDomain_UsesUnknownNotApp verifies that when Site exists but has no domain/page, we send site_domain=unknown and do NOT use App. +func TestMakeRequests_SitePresentWithEmptyDomain_UsesUnknownNotApp(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-domain-2", + Site: &openrtb2.Site{ + Domain: "", + Publisher: &openrtb2.Publisher{ + Domain: "dev.sparteo.com", + }, + }, + App: &openrtb2.App{ + Domain: "app.sparteo.com", + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Len(t, errs, 1) + + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=unknown", + reqs[0].Uri, + ) +} + +// TestMakeRequests_DomainPrecedence_AppDomainWhenNoSite verifies that if there is no Site, we use app.domain (and include bundle if present). +func TestMakeRequests_DomainPrecedence_AppDomainWhenNoSite(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-domain-3", + Site: nil, + App: &openrtb2.App{ + Domain: "app.sparteo.com", + Bundle: "com.sparteo.app", + Publisher: &openrtb2.Publisher{ + Domain: "app-pub.should-not-be-used", + }, + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&app_domain=app.sparteo.com&bundle=com.sparteo.app", + reqs[0].Uri, + ) +} + +// TestMakeRequests_SitePageWhenNoSiteDomainNoApp verifies that if there is Site without domain but page is present, we use site.page. +func TestMakeRequests_SitePageWhenNoSiteDomainNoApp(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-domain-page", + Site: &openrtb2.Site{ + Domain: "", + Page: "https://www.dev.sparteo.com:3000/some/path?x=1", + }, + App: nil, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=dev.sparteo.com", + reqs[0].Uri, + ) +} + +// TestNormalizeHostname_PortAndPathAndURL verifies normalizeHostname behavior. +func TestNormalizeHostname_PortAndPathAndURL(t *testing.T) { + base := "dev.sparteo.com" + + tests := []struct { + name string + in string + out string + }{ + // Bare host + port + {"host_with_port", "www." + base + ":8080", base}, + {"host_upper_with_tls_port", "DEV.SPARTEO.COM:443", base}, + {"host_trailing_dot_with_port", base + ".:8443", base}, + + // Bare host + path + {"host_with_path", base + "/some/path?x=1", base}, + {"www_host_with_path", "www." + base + "/p", base}, + + // Bare host + port + path + {"host_with_port_and_path", base + ":8080/p?q=1", base}, + {"www_host_with_port_and_path", "www." + base + ":3000/some/path", base}, + + // Absolute URLs + {"https_url", "https://www." + base + "/x", base}, + {"http_url_with_port", "http://WWW." + base + ":8080/abc", base}, + + // Scheme-relative URL + {"scheme_relative", "//www." + base + "/x", base}, + + // Odd spacing around URLs/hosts + {"spaced_https_url", " https://www." + base + ":3000/x ", base}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := normalizeHostname(tc.in) + assert.Equal(t, tc.out, got) + }) + } +} + +// --- Helper for reading publisher.ext.params.networkId in output JSON --- +func readNetworkIDFromPublisherExt(t *testing.T, ext json.RawMessage) (string, bool) { + if len(ext) == 0 { + return "", false + } + var m map[string]interface{} + require.NoError(t, json.Unmarshal(ext, &m)) + params, _ := m["params"].(map[string]interface{}) + if params == nil { + return "", false + } + val, _ := params["networkId"].(string) + if val == "" { + return "", false + } + return val, true +} + +// When site exists but site.publisher is nil, the adapter must create publisher and upsert networkId into site.publisher.ext +func TestMakeRequests_UpdatePublisherExtension_CreatesSitePublisherIfMissing(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-upsert-site", + Site: &openrtb2.Site{ + Domain: "site.sparteo.com", + Publisher: nil, + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + + require.NotNil(t, out.Site) + require.NotNil(t, out.Site.Publisher, "publisher should be created when missing") + val, ok := readNetworkIDFromPublisherExt(t, out.Site.Publisher.Ext) + require.True(t, ok, "site.publisher.ext.params.networkId should exist") + assert.Equal(t, "networkID", val) +} + +// When no site is present, create app.publisher if missing and upsert networkId into app.publisher.ext +func TestMakeRequests_UpdatePublisherExtension_CreatesAppPublisherIfMissingWhenNoSite(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-upsert-app", + Site: nil, + App: &openrtb2.App{ + Domain: "app.sparteo.com", + Bundle: "com.sparteo.app", + Publisher: nil, + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + + require.Nil(t, out.Site) + require.NotNil(t, out.App) + require.NotNil(t, out.App.Publisher, "app.publisher should be created when missing") + val, ok := readNetworkIDFromPublisherExt(t, out.App.Publisher.Ext) + require.True(t, ok, "app.publisher.ext.params.networkId should exist") + assert.Equal(t, "networkID", val) +} + +// TestMakeRequests_UpdatePublisherExtension_PrefersSiteOverApp verifies that we prefer Site when both Site and App exist; only Site should receive the networkId +func TestMakeRequests_UpdatePublisherExtension_PrefersSiteOverApp(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-upsert-prefer-site", + Site: &openrtb2.Site{ + Domain: "site.sparteo.com", + Publisher: &openrtb2.Publisher{}, + }, + App: &openrtb2.App{ + Domain: "app.sparteo.com", + Publisher: &openrtb2.Publisher{}, + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + + require.NotNil(t, out.Site) + require.NotNil(t, out.Site.Publisher) + siteVal, siteOk := readNetworkIDFromPublisherExt(t, out.Site.Publisher.Ext) + require.True(t, siteOk) + assert.Equal(t, "networkID", siteVal) + + if out.App != nil && out.App.Publisher != nil { + _, appOk := readNetworkIDFromPublisherExt(t, out.App.Publisher.Ext) + assert.False(t, appOk, "app.publisher.ext should not contain networkId when site exists") + } +} + +// TestMakeRequests_NoSiteNoApp_NoDomainParam_NoWarning verifies that with neither Site nor App we don't send domain params and produce no warnings. +func TestMakeRequests_NoSiteNoApp_NoDomainParam_NoWarning(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-domain-missing", + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + + require.Len(t, reqs, 1) + require.Len(t, errs, 0) + + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID", + reqs[0].Uri, + ) +} + +// TestMakeRequests_SitePageLiteralNull_TreatedAsMissingDomain verifies that a literal "null" in site.page is treated as an unknown site domain. +func TestMakeRequests_SitePageLiteralNull_TreatedAsMissingDomain(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s-auction" + + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + ID: "req-page-null", + Site: &openrtb2.Site{ + Domain: "", + Page: "null", + }, + Imp: []openrtb2.Imp{ + {ID: "imp-1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}, + }, + } + + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + + require.Len(t, reqs, 1) + require.Len(t, errs, 1) + assert.Equal(t, + "https://bid-test.sparteo.com/s2s-auction?network_id=networkID&site_domain=unknown", + reqs[0].Uri, + ) + + var badInput *errortypes.BadInput + require.True(t, errors.As(errs[0], &badInput)) + assert.Contains(t, badInput.Error(), "Domain not found") +} + +// TestMakeRequests_AppBundle_NormalizationVariants ensures blank/whitespace/"null" bundles normalize to "unknown" with a single warning. +func TestMakeRequests_AppBundle_NormalizationVariants(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + cases := []struct { + name string + bundle string + }{ + {"empty", ""}, + {"spaces", " "}, + {"lower_null", "null"}, + {"weird_case", "NuLl"}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + in := &openrtb2.BidRequest{ + App: &openrtb2.App{Domain: "dev.sparteo.com", Bundle: tc.bundle, Publisher: &openrtb2.Publisher{}}, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":"n"}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Len(t, errs, 1) + assert.Contains(t, reqs[0].Uri, "app_domain=dev.sparteo.com") + assert.Contains(t, reqs[0].Uri, "bundle=unknown") + var badInput *errortypes.BadInput + require.True(t, errors.As(errs[0], &badInput)) + assert.Contains(t, badInput.Error(), "Bundle not found") + }) + } +} + +// TestMakeRequests_SitePresent_IgnoresAppFields ensures when Site is present, only site_domain is sent and app fields are ignored. +func TestMakeRequests_SitePresent_IgnoresAppFields(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "site.sparteo.com"}, + App: &openrtb2.App{Domain: "app.sparteo.com", Bundle: "com.app"}, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":"N"}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + assert.Equal(t, "https://bid-test.sparteo.com/s2s?network_id=N&site_domain=site.sparteo.com", reqs[0].Uri) +} + +// TestMakeRequests_SiteWithPageFallback_IgnoresApp ensures Site.Page is used when Site.Domain is empty and App is ignored when Site exists. +func TestMakeRequests_SiteWithPageFallback_IgnoresApp(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "", Page: "https://www.example.com:8080/p"}, + App: &openrtb2.App{Domain: "app.sparteo.com", Bundle: "com.app"}, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + assert.Equal(t, "https://bid-test.sparteo.com/s2s?network_id=networkID&site_domain=example.com", reqs[0].Uri) +} + +// TestMakeRequests_AppMissingBundle_WarnsAndUnknown ensures App with missing bundle yields bundle=unknown and one bundle warning. +func TestMakeRequests_AppMissingBundle_WarnsAndUnknown(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + App: &openrtb2.App{Domain: "dev.sparteo.com", Bundle: "", Publisher: &openrtb2.Publisher{}}, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":"networkID"}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Len(t, errs, 1) + assert.Equal(t, "https://bid-test.sparteo.com/s2s?network_id=networkID&app_domain=dev.sparteo.com&bundle=unknown", reqs[0].Uri) + var badInput *errortypes.BadInput + require.True(t, errors.As(errs[0], &badInput)) + assert.Contains(t, badInput.Error(), "Bundle not found") +} + +// TestMakeRequests_ExtRewrite_MovesBidderIntoSparteoParams verifies bidder object is moved under sparteo.params and bidder is removed. +func TestMakeRequests_ExtRewrite_MovesBidderIntoSparteoParams(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "dev.sparteo.com"}, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"a":1}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + var ext map[string]any + require.NoError(t, json.Unmarshal(out.Imp[0].Ext, &ext)) + _, hasBidder := ext["bidder"] + assert.False(t, hasBidder) + sparteoNode, ok := ext["sparteo"].(map[string]any) + require.True(t, ok) + params, ok := sparteoNode["params"].(map[string]any) + require.True(t, ok) + assert.Equal(t, float64(1), params["a"]) +} + +// TestMakeRequests_ExtRewrite_PreservesExistingSparteoParams verifies existing sparteo.params keys are preserved when merging bidder fields. +func TestMakeRequests_ExtRewrite_PreservesExistingSparteoParams(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "dev.sparteo.com"}, + Imp: []openrtb2.Imp{{ + ID: "i1", + Ext: json.RawMessage(`{"sparteo":{"params":{"keep":true}},"bidder":{"add":42}}`), + }}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + var ext map[string]any + require.NoError(t, json.Unmarshal(out.Imp[0].Ext, &ext)) + sparteoNode, ok := ext["sparteo"].(map[string]any) + require.True(t, ok) + params, ok := sparteoNode["params"].(map[string]any) + require.True(t, ok) + assert.Equal(t, true, params["keep"]) + assert.Equal(t, float64(42), params["add"]) +} + +// TestMakeRequests_NetworkId_FirstNonEmptyWins verifies the first non-empty networkId across imps is used. +func TestMakeRequests_NetworkId_FirstNonEmptyWins(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "dev.sparteo.com"}, + Imp: []openrtb2.Imp{ + {ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":""}}`)}, + {ID: "i2", Ext: json.RawMessage(`{"bidder":{"networkId":"N2"}}`)}, + {ID: "i3", Ext: json.RawMessage(`{"bidder":{"networkId":"N3"}}`)}, + }, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + assert.Equal(t, "https://bid-test.sparteo.com/s2s?network_id=N2&site_domain=dev.sparteo.com", reqs[0].Uri) +} + +// TestMakeRequests_AllImpsBadExt_AggregatesErrors verifies a request is still built when all imps have bad ext and errors are aggregated. +func TestMakeRequests_AllImpsBadExt_AggregatesErrors(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Domain: "dev.sparteo.com"}, + Imp: []openrtb2.Imp{ + {ID: "i1", Ext: json.RawMessage(`not-json`)}, + {ID: "i2", Ext: json.RawMessage(`{"bidder":}`)}, + }, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Len(t, errs, 2) + assert.Equal(t, "https://bid-test.sparteo.com/s2s?network_id=&site_domain=dev.sparteo.com", reqs[0].Uri) +} + +// TestMakeRequests_UpdatePublisherExtension_PreservesOtherKeys verifies publisher.ext keeps existing keys while adding params.networkId. +func TestMakeRequests_UpdatePublisherExtension_PreservesOtherKeys(t *testing.T) { + endpoint := "https://bid-test.sparteo.com/s2s" + bidder, err := Builder(openrtb_ext.BidderSparteo, config.Adapter{Endpoint: endpoint}, config.Server{GvlID: 1028}) + require.NoError(t, err) + + startExt := json.RawMessage(`{"params":{"foo":"bar"},"other":123}`) + in := &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Domain: "dev.sparteo.com", + Publisher: &openrtb2.Publisher{Ext: startExt}, + }, + Imp: []openrtb2.Imp{{ID: "i1", Ext: json.RawMessage(`{"bidder":{"networkId":"N"}}`)}}, + } + reqs, errs := bidder.MakeRequests(in, &adapters.ExtraRequestInfo{}) + require.Len(t, reqs, 1) + require.Empty(t, errs) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(reqs[0].Body, &out)) + var m map[string]any + require.NoError(t, json.Unmarshal(out.Site.Publisher.Ext, &m)) + params, _ := m["params"].(map[string]any) + require.NotNil(t, params) + assert.Equal(t, "bar", params["foo"]) + assert.Equal(t, float64(123), m["other"]) + assert.Equal(t, "N", params["networkId"]) +} + +// TestMakeBids_SkipsAudioBids verifies bids with prebid.type=audio are skipped with no returned errors. +func TestMakeBids_SkipsAudioBids(t *testing.T) { + a := &adapter{} + body := []byte(`{"cur":"USD","seatbid":[{"bid":[{"impid":"1","price":1,"crid":"c","ext":{"prebid":{"type":"audio"}}}]}]}`) + br, errs := a.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: 200, Body: body}) + require.NoError(t, nil) + require.Nil(t, errs) + require.NotNil(t, br) + assert.Equal(t, 0, len(br.Bids)) +} + +// TestMakeBids_SetsMTypeAndCurrency verifies mtype is set correctly for banner/video/native and currency is propagated. +func TestMakeBids_SetsMTypeAndCurrency(t *testing.T) { + a := &adapter{} + body := []byte(`{ + "cur":"EUR", + "seatbid":[{"bid":[ + {"impid":"b1","price":1,"crid":"c1","ext":{"prebid":{"type":"banner"}}}, + {"impid":"v1","price":2,"crid":"c2","ext":{"prebid":{"type":"video"}}}, + {"impid":"n1","price":3,"crid":"c3","ext":{"prebid":{"type":"native"}}} + ]}] + }`) + br, errs := a.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: 200, Body: body}) + require.Nil(t, errs) + require.NotNil(t, br) + require.Equal(t, "EUR", br.Currency) + require.Equal(t, 3, len(br.Bids)) + assert.Equal(t, openrtb2.MarkupBanner, br.Bids[0].Bid.MType) + assert.Equal(t, openrtb2.MarkupVideo, br.Bids[1].Bid.MType) + assert.Equal(t, openrtb2.MarkupNative, br.Bids[2].Bid.MType) +} diff --git a/adapters/sparteo/sparteotest/exemplary/banner-app.json b/adapters/sparteo/sparteotest/exemplary/banner-app.json new file mode 100644 index 0000000000..1e88391f3e --- /dev/null +++ b/adapters/sparteo/sparteotest/exemplary/banner-app.json @@ -0,0 +1,242 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "topframe": 1, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "networkId": "networkId" + } + } + } + ], + "app": { + "domain": "dev.sparteo.com", + "bundle": "com.sparteo.app", + "publisher": { + "domain": "dev.sparteo.com", + "id": "sparteo" + } + }, + "device": { + "w": 1920, + "h": 1080, + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + }, + "sua": { + "source": 1, + "platform": { + "brand": "macOS" + }, + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "mobile": 0 + } + }, + "ext": { + "prebid": { + "server": { + "datacenter": "", + "externalurl": "", + "gvlid": 1028 + } + }, + "tmaxmax": 5000 + }, + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&app_domain=dev.sparteo.com&bundle=com.sparteo.app", + "body": { + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "sparteo": { + "params": { + "networkId": "networkId" + } + } + } + } + ], + "app": { + "domain": "dev.sparteo.com", + "bundle": "com.sparteo.app", + "publisher": { + "domain": "dev.sparteo.com", + "id": "sparteo", + "ext": { + "params": { + "networkId": "networkId" + } + } + } + }, + "device": { + "dnt": 0, + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "sua": { + "browsers": [ + { + "brand": "Chromium", + "version": [ + "134" + ] + }, + { + "brand": "Not:A-Brand", + "version": [ + "24" + ] + }, + { + "brand": "Google Chrome", + "version": [ + "134" + ] + } + ], + "platform": { + "brand": "macOS" + }, + "mobile": 0, + "source": 1 + }, + "h": 1080, + "w": 1920, + "language": "fr", + "ext": { + "vpw": 1056, + "vph": 934 + } + }, + "tmax": 5000, + "ext": { + "prebid": { + "server": { + "externalurl": "", + "gvlid": 1028, + "datacenter": "" + } + }, + "tmaxmax": 5000 + } + }, + "impIDs": [ + "div-banner-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "request-id", + "seatbid": [ + { + "seat": "sparteo", + "bid": [ + { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "price": 0.10797, + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "<script></script>", + "adomain": [ + "testpage-ad" + ], + "crid": "banner_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "banner" + } + } + } + ] + + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "request-id", + "bids": [ + { + "bid": { + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "mtype": 1, + "price": 0.10797, + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "<script></script>", + "adomain": [ + "testpage-ad" + ], + "crid": "banner_creative_test", + "w": 300, + "h": 250, + "ext": { + "ft": "passthrough", + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "cur": "EUR" + } + ] +} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/exemplary/banner.json b/adapters/sparteo/sparteotest/exemplary/banner.json index 78fa09afc7..f68f57b633 100644 --- a/adapters/sparteo/sparteotest/exemplary/banner.json +++ b/adapters/sparteo/sparteotest/exemplary/banner.json @@ -21,13 +21,13 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "publisher": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "id": "sparteo" }, - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/" + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/" }, "device": { "w": 1920, @@ -82,7 +82,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -107,12 +107,12 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/", + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/", "publisher": { "id": "sparteo", - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "ext": { "params": { "networkId": "networkId" @@ -186,7 +186,7 @@ "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", "impid": "div-banner-id", "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" @@ -220,7 +220,7 @@ "impid": "div-banner-id", "mtype": 1, "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" diff --git a/adapters/sparteo/sparteotest/exemplary/native.json b/adapters/sparteo/sparteotest/exemplary/native.json index 2f5b9bcc34..bcbbf8b6ab 100644 --- a/adapters/sparteo/sparteotest/exemplary/native.json +++ b/adapters/sparteo/sparteotest/exemplary/native.json @@ -15,13 +15,13 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "publisher": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "id": "sparteo" }, - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/" + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/" }, "device": { "w": 1920, @@ -76,7 +76,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -95,12 +95,12 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/", + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/", "publisher": { "id": "sparteo", - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "ext": { "params": { "networkId": "networkId" @@ -174,7 +174,7 @@ "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", "impid": "div-native-id", "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" @@ -207,7 +207,7 @@ "impid": "div-native-id", "mtype": 4, "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" diff --git a/adapters/sparteo/sparteotest/exemplary/video.json b/adapters/sparteo/sparteotest/exemplary/video.json index f69d646309..12a8c578be 100644 --- a/adapters/sparteo/sparteotest/exemplary/video.json +++ b/adapters/sparteo/sparteotest/exemplary/video.json @@ -43,13 +43,13 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "publisher": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "id": "sparteo" }, - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/" + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/" }, "device": { "w": 1920, @@ -104,7 +104,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -146,12 +146,12 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/", + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/", "publisher": { "id": "sparteo", - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "ext": { "params": { "networkId": "networkId" @@ -225,7 +225,7 @@ "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", "impid": "div-video-id", "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" @@ -258,7 +258,7 @@ "impid": "div-video-id", "mtype": 2, "price": 0.10797, - "nurl": "https://dev.sparteo.com:4444/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", "adm": "<script></script>", "adomain": [ "testpage-ad" diff --git a/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json b/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json index ded36e22d4..ba66d5820b 100644 --- a/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json +++ b/adapters/sparteo/sparteotest/supplemental/filter-empty-seat-bids.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "test-request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json b/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json index 851fcf1860..ab31a8e67e 100644 --- a/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json +++ b/adapters/sparteo/sparteotest/supplemental/filter-invalid-bid-type.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "test-request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": ["div-banner-id"] }, diff --git a/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json b/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json index 21e3f35629..0660aee07c 100644 --- a/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json +++ b/adapters/sparteo/sparteotest/supplemental/filter-no-seat-bids.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "test-request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json b/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json deleted file mode 100644 index 61d1d61002..0000000000 --- a/adapters/sparteo/sparteotest/supplemental/invalid-bidder-ext.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "imp": [ - { - "id": "div-banner-id", - "banner": { - "topframe": 1, - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": "not an object" - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "div-banner-id", - "banner": { - "topframe": 1, - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { - "bidder": "not an object" - } - } - ] - }, - "ImpIDs": ["div-banner-id"] - }} - ], - "expectedMakeRequestsErrors": [ - { - "value": "^ignoring imp id=div-banner-id, error while decoding impExt", - "comparison": "regex" - } - ], - "expectedMakeBidsErrors": [ - { - "value": "Unexpected status code: 0. Run with request.debug = 1 for more info", - "comparison": "literal" - } - ] -} \ No newline at end of file diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json b/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json index 12ad55425b..adb997a503 100644 --- a/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json +++ b/adapters/sparteo/sparteotest/supplemental/invalid-json-response.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "test-request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json b/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json index 5d2bb2148c..73a196772a 100644 --- a/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json +++ b/adapters/sparteo/sparteotest/supplemental/invalid-publisher-ext.json @@ -21,12 +21,12 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", - "page": "https://dev.sparteo.com:4444/page/test/", - "ref": "https://dev.sparteo.com:4444/page/test/", + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/", "publisher": { "id": "sparteo", - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "ext": "not an object" } } @@ -34,7 +34,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "test-request-id", "imp": [ @@ -59,10 +59,10 @@ } ], "site": { - "domain": "dev.sparteo.com:4444", - "page": "https://dev.sparteo.com:4444/page/test/", + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", "publisher": { - "domain": "dev.sparteo.com:4444", + "domain": "dev.sparteo.com", "ext": { "params": { "networkId": "networkId" @@ -70,7 +70,7 @@ }, "id": "sparteo" }, - "ref": "https://dev.sparteo.com:4444/page/test/" + "ref": "https://dev.sparteo.com/page/test/" } }, "impIDs": [ diff --git a/adapters/sparteo/sparteotest/supplemental/status_204.json b/adapters/sparteo/sparteotest/supplemental/status_204.json index 171eec08ed..7358403bf6 100644 --- a/adapters/sparteo/sparteotest/supplemental/status_204.json +++ b/adapters/sparteo/sparteotest/supplemental/status_204.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/adapters/sparteo/sparteotest/supplemental/status_400.json b/adapters/sparteo/sparteotest/supplemental/status_400.json index 26f24b68be..d97b7f083c 100644 --- a/adapters/sparteo/sparteotest/supplemental/status_400.json +++ b/adapters/sparteo/sparteotest/supplemental/status_400.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/adapters/sparteo/sparteotest/supplemental/status_500.json b/adapters/sparteo/sparteotest/supplemental/status_500.json index ec3c68e56b..bee2affa48 100644 --- a/adapters/sparteo/sparteotest/supplemental/status_500.json +++ b/adapters/sparteo/sparteotest/supplemental/status_500.json @@ -19,12 +19,15 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com" + } }, "httpCalls": [ { "expectedRequest": { - "uri": "https://bid-test.sparteo.com/s2s-auction", + "uri": "https://bid-test.sparteo.com/s2s-auction?network_id=networkId&site_domain=dev.sparteo.com", "body": { "id": "request-id", "imp": [ @@ -47,7 +50,17 @@ } } } - ] + ], + "site": { + "domain": "dev.sparteo.com", + "publisher": { + "ext": { + "params": { + "networkId": "networkId" + } + } + } + } }, "impIDs": [ "div-banner-id" diff --git a/macros/macros.go b/macros/macros.go index 0c6e08cae0..2473be05e7 100644 --- a/macros/macros.go +++ b/macros/macros.go @@ -25,6 +25,10 @@ type EndpointTemplateParams struct { PartnerId string Region string PlacementID string + NetworkId string + SiteDomain string + AppDomain string + Bundle string } // UserSyncPrivacy specifies privacy policy macros, represented as strings, for user sync urls. diff --git a/static/bidder-info/sparteo.yaml b/static/bidder-info/sparteo.yaml index c1f862ed06..f9270be721 100644 --- a/static/bidder-info/sparteo.yaml +++ b/static/bidder-info/sparteo.yaml @@ -16,4 +16,4 @@ capabilities: endpoint: "https://bid.sparteo.com/s2s-auction" userSync: iframe: - url: "https://sync.sparteo.com/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect_url={{.RedirectURL}}" \ No newline at end of file + url: "https://sync.sparteo.com/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect_url={{.RedirectURL}}" From 48a6be239e1cad34772758f3f07bc80e4076d1b1 Mon Sep 17 00:00:00 2001 From: Tjorven <t.beckedorf@emetriq.com> Date: Tue, 12 May 2026 18:52:02 +0200 Subject: [PATCH 208/272] New Adapter: T Advertising Blis (#4706) --- adapters/tadvertising_blis/params_test.go | 66 ++++ .../tadvertising_blis/tadvertising_blis.go | 151 +++++++++ .../tadvertising_blis_test.go | 20 ++ .../exemplary/banner.json | 229 +++++++++++++ .../exemplary/native.json | 131 ++++++++ .../exemplary/video.json | 153 +++++++++ .../supplemental/banner_no_publisher.json | 226 +++++++++++++ .../supplemental/banner_no_publisher_id.json | 228 +++++++++++++ .../banner_no_publisher_id_in_app.json | 228 +++++++++++++ .../banner_no_publisher_in_app.json | 226 +++++++++++++ .../supplemental/banner_no_site.json | 224 +++++++++++++ .../supplemental/bid-macro-replace.json | 233 +++++++++++++ .../supplemental/invalid-imp-ext-bidder.json | 18 ++ .../supplemental/invalid-imp-ext.json | 17 + .../supplemental/multiImpressionsRequest.json | 305 ++++++++++++++++++ .../supplemental/response-http-204.json | 57 ++++ .../supplemental/response-http-500.json | 61 ++++ .../supplemental/unsupported-media-type.json | 93 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_tadvertisingblis.go | 5 + static/bidder-info/tadvertising_blis.yaml | 21 ++ static/bidder-params/tadvertising_blis.json | 17 + 23 files changed, 2713 insertions(+) create mode 100644 adapters/tadvertising_blis/params_test.go create mode 100644 adapters/tadvertising_blis/tadvertising_blis.go create mode 100644 adapters/tadvertising_blis/tadvertising_blis_test.go create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/exemplary/banner.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/exemplary/native.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/exemplary/video.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id_in_app.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_in_app.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_site.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/bid-macro-replace.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext-bidder.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/multiImpressionsRequest.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-204.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-500.json create mode 100644 adapters/tadvertising_blis/tadvertising_blistest/supplemental/unsupported-media-type.json create mode 100644 openrtb_ext/imp_tadvertisingblis.go create mode 100644 static/bidder-info/tadvertising_blis.yaml create mode 100644 static/bidder-params/tadvertising_blis.json diff --git a/adapters/tadvertising_blis/params_test.go b/adapters/tadvertising_blis/params_test.go new file mode 100644 index 0000000000..6e3d5ad138 --- /dev/null +++ b/adapters/tadvertising_blis/params_test.go @@ -0,0 +1,66 @@ +package tadvertising_blis + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type testSpec struct { + name string + json string + wantErr bool +} + +func testParams(t *testing.T, specs []testSpec) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema") + + for _, spec := range specs { + t.Run(spec.name, func(t *testing.T) { + err := validator.Validate(openrtb_ext.BidderTAdvertisingBlis, json.RawMessage(spec.json)) + if spec.wantErr { + assert.Error(t, err, "Expected error but got none for: %s", spec.json) + } else { + assert.NoError(t, err, "Unexpected error for: %s", spec.json) + } + }) + } +} + +func TestValidParams(t *testing.T) { + testParams(t, []testSpec{ + { + name: "Valid params with publisherId", + json: `{"publisherId": "1427ab10f2e448057ed3b422"}`, + }, + }) +} + +func TestInvalidParams(t *testing.T) { + testParams(t, []testSpec{ + { + name: "Empty params", + json: `{}`, + wantErr: true, + }, + { + name: "Empty publisherId", + json: `{"publisherId": ""}`, + wantErr: true, + }, + { + name: "Invalid publisherId type", + json: `{"publisherId": 123}`, + wantErr: true, + }, + { + name: "Too long publisherId", + json: `{"publisherId": "111111111111111111111111111111111"}`, + wantErr: true, + }, + }) +} diff --git a/adapters/tadvertising_blis/tadvertising_blis.go b/adapters/tadvertising_blis/tadvertising_blis.go new file mode 100644 index 0000000000..982f73d2e3 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blis.go @@ -0,0 +1,151 @@ +package tadvertising_blis + +import ( + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iterutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{} + bidder.endpoint = config.Endpoint + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var impExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[0].Ext, &impExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Information: %v", 0, err), + }} + } + var impExtBidder openrtb_ext.ImpExtTadvertising + if err := jsonutil.Unmarshal(impExt.Bidder, &impExtBidder); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext.bidder for impression index %d. Error Information: %v", 0, err), + }} + } + + if request.Site != nil && request.App == nil { + siteCopy := *request.Site + request.Site = &siteCopy + + if request.Site.Publisher != nil { + sitePublisherCopy := *request.Site.Publisher + request.Site.Publisher = &sitePublisherCopy + request.Site.Publisher.ID = impExtBidder.PublisherId + } else { + request.Site.Publisher = &openrtb2.Publisher{} + request.Site.Publisher.ID = impExtBidder.PublisherId + } + } else if request.App != nil { + appCopy := *request.App + request.App = &appCopy + + if request.App.Publisher != nil { + appPublisherCopy := *request.App.Publisher + request.App.Publisher = &appPublisherCopy + request.App.Publisher.ID = impExtBidder.PublisherId + } else { + request.App.Publisher = &openrtb2.Publisher{} + request.App.Publisher.ID = impExtBidder.PublisherId + } + } else { + request.Site = &openrtb2.Site{} + request.Site.Publisher = &openrtb2.Publisher{} + request.Site.Publisher.ID = impExtBidder.PublisherId + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json") + headers.Add("X-Supply-Partner-Id", impExtBidder.PublisherId) + + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Headers: headers, + Body: requestJSON, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + + var errors []error + for seatBid := range iterutil.SlicePointerValues(response.SeatBid) { + for bid := range iterutil.SlicePointerValues(seatBid.Bid) { + resolveMacros(bid) + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + return bidResponse, errors +} + +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 + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse media type of impression ID \"%s\"", bid.ImpID), + } + } +} + +func resolveMacros(bid *openrtb2.Bid) { + if bid != nil { + price := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.NURL = strings.ReplaceAll(bid.NURL, "${AUCTION_PRICE}", price) + bid.AdM = strings.ReplaceAll(bid.AdM, "${AUCTION_PRICE}", price) + bid.BURL = strings.ReplaceAll(bid.BURL, "${AUCTION_PRICE}", price) + } +} diff --git a/adapters/tadvertising_blis/tadvertising_blis_test.go b/adapters/tadvertising_blis/tadvertising_blis_test.go new file mode 100644 index 0000000000..a68a35bfc1 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blis_test.go @@ -0,0 +1,20 @@ +package tadvertising_blis + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderTAdvertisingBlis, config.Adapter{ + Endpoint: "https://example.endpoint/"}, + config.Server{ExternalUrl: "http://example.server", GvlID: 1, DataCenter: "2"}) + + require.NoError(t, buildErr) + + adapterstest.RunJSONBidderTest(t, "tadvertising_blistest", bidder) +} diff --git a/adapters/tadvertising_blis/tadvertising_blistest/exemplary/banner.json b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/banner.json new file mode 100644 index 0000000000..78b8ccb3ee --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/banner.json @@ -0,0 +1,229 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/exemplary/native.json b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/native.json new file mode 100644 index 0000000000..6166d024a9 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/native.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}},{\"id\":3,\"data\":{\"type\":2}}]}", + "ver": "1.2" + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "cur": ["USD"], + "site": { + "publisher": { + "domain": "example.com" + }, + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "cat": ["site-cat"] + }, + "device": { + "w": 1434, + "h": 686, + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": ["testimp"], + "body": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":100}},{\"id\":3,\"data\":{\"type\":2}}]}", + "ver": "1.2" + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "cat": ["site-cat"], + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "publisher": { + "domain": "example.com", + "id": "123" + } + }, + "device": { + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8", + "h": 686, + "w": 1434 + }, + "cur": ["USD"] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123456789", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.3, + "crid": "9999999", + "adomain": ["example.com"], + "cid": "999999", + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Native Ad Title\"}},{\"id\":2,\"img\":{\"url\":\"https://adserverexample.com/image.jpg\",\"w\":1200,\"h\":627}},{\"id\":3,\"data\":{\"value\":\"Sponsored\"}}],\"link\":{\"url\":\"https://clickexample.com\"},\"imptrackers\":[\"https://trackingexample.com/pixel?wp=${AUCTION_PRICE}\"]}}", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 4 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "1", + "impid": "testimp", + "price": 1.3, + "crid": "9999999", + "adomain": ["example.com"], + "cid": "999999", + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Native Ad Title\"}},{\"id\":2,\"img\":{\"url\":\"https://adserverexample.com/image.jpg\",\"w\":1200,\"h\":627}},{\"id\":3,\"data\":{\"value\":\"Sponsored\"}}],\"link\":{\"url\":\"https://clickexample.com\"},\"imptrackers\":[\"https://trackingexample.com/pixel?wp=1.3\"]}}", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=1.3", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/exemplary/video.json b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/video.json new file mode 100644 index 0000000000..352111a98e --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/exemplary/video.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "123456789", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "testimp", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "bidfloor": 0.98, + "bidfloorcur": "USD" + } + ], + "cur": [ + "USD" + ], + "site": { + "publisher": { + "domain": "example.com" + }, + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "cat": [ + "site-cat" + ] + }, + "device": { + "w": 1434, + "h": 686, + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "testimp" + ], + "body": { + "id": "123456789", + "imp": [ + { + "id": "testimp", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "bidfloor": 0.98, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "cat": [ + "site-cat" + ], + "page": "http://lh.example.com/prebid_server_kitchen_sink.html?pbjs_debug=true", + "publisher": { + "id": "123", + "domain": "example.com" + } + }, + "device": { + "geo": { + "country": "USA" + }, + "ip": "8.8.8.8", + "h": 686, + "w": 1434 + }, + "cur": [ + "USD" + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123456789", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.5, + "crid": "9999999", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "cid": "999999", + "adm": "<VAST version=\"2.0\"><Ad id=\"9999999\"><Wrapper><AdSystem>blistracker</AdSystem><VASTAdTagURI><![CDATA[https://example.com/video.mp4]]></VASTAdTagURI><Impression><![CDATA[https://trackingexample.com/pixel]]></Impression><Creatives/></Wrapper></Ad></VAST>", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "1", + "impid": "testimp", + "price": 1.5, + "crid": "9999999", + "w": 640, + "h": 480, + "adomain": ["example.com"], + "cid": "999999", + "adm": "<VAST version=\"2.0\"><Ad id=\"9999999\"><Wrapper><AdSystem>blistracker</AdSystem><VASTAdTagURI><![CDATA[https://example.com/video.mp4]]></VASTAdTagURI><Impression><![CDATA[https://trackingexample.com/pixel]]></Impression><Creatives/></Wrapper></Ad></VAST>", + "cat": ["IAB3-1"], + "burl": "https://trackingexample.com/pixel?wp=1.5", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher.json new file mode 100644 index 0000000000..427a68da63 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher.json @@ -0,0 +1,226 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "site": { + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id.json new file mode 100644 index 0000000000..06b0079923 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id.json @@ -0,0 +1,228 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "site": { + "publisher": { + } + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id_in_app.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id_in_app.json new file mode 100644 index 0000000000..5d490352a0 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_id_in_app.json @@ -0,0 +1,228 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "app": { + "publisher": { + } + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + }, + "app": { + "publisher": { + "id": "123" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_in_app.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_in_app.json new file mode 100644 index 0000000000..bb88055867 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_publisher_in_app.json @@ -0,0 +1,226 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "app": { + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + }, + "app": { + "publisher": { + "id": "123" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_site.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_site.json new file mode 100644 index 0000000000..f245874aa0 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/banner_no_site.json @@ -0,0 +1,224 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/bid-macro-replace.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/bid-macro-replace.json new file mode 100644 index 0000000000..de11c040f3 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/bid-macro-replace.json @@ -0,0 +1,233 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 2.3, + "protocol": 0, + "adm": "<html><h3>I am an ad and cost ${AUCTION_PRICE}</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ], + "nurl": "https://test.com/${AUCTION_PRICE}", + "burl": "https://test.com/${AUCTION_PRICE}" + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 2.3, + "mtype": 1, + "adm": "<html><h3>I am an ad and cost 2.3</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ], + "nurl": "https://test.com/2.3", + "burl": "https://test.com/2.3" + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext-bidder.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext-bidder.json new file mode 100644 index 0000000000..2d0e1a270c --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext-bidder.json @@ -0,0 +1,18 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp", + "ext": {} + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext.bidder for impression", + "comparison": "startswith" + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..31e261e6fa --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/invalid-imp-ext.json @@ -0,0 +1,17 @@ +{ + "mockBidRequest": { + "id": "test-request", + "imp": [ + { + "id": "test-imp" + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext for impression", + "comparison": "startswith" + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/multiImpressionsRequest.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/multiImpressionsRequest.json new file mode 100644 index 0000000000..4108487e0e --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/multiImpressionsRequest.json @@ -0,0 +1,305 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id", + "bidfloor": 0, + "secure": 1 + }, + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id2", + "banner": { + "w": 300, + "h": 250, + "pos": 0, + "api": [ + ] + }, + "tagid": "test-tag-id2", + "bidfloor": 0, + "secure": 1 + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "deviceType": 2, + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "pid": "test-pid", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "coppa": 0, + "gdpr": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "headers": { + "Content-Type": ["application/json"], + "X-Supply-Partner-Id": ["123"] + }, + "impIDs": [ + "test-impression-id", + "test-impression-id2" + ], + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id", + "secure": 1, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }, + { + "ext": { + "bidder": { + "publisherId": "123" + } + }, + "id": "test-impression-id2", + "banner": { + "w": 300, + "h": 250, + "pos": 0 + }, + "tagid": "test-tag-id2", + "secure": 1 + } + ], + "site": { + "publisher": { + "id": "123" + } + }, + "device": { + "devicetype": 2, + "ua": "test-user-agent", + "geo": { + "country": "US" + }, + "dnt": 0, + "lmt": 0, + "ip": "127.0.0.1", + "make": "test-make", + "model": "test-model", + "os": "test-os", + "osv": "test-osv", + "h": 1080, + "w": 1920, + "language": "en", + "ifa": "test-ifa" + }, + "test": 1, + "at": 1, + "tmax": 100, + "source": { + "fd": 1, + "tid": "test-transaction-id", + "pchain": "test-pchain", + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "test-asi", + "sid": "test-sid", + "rid": "test-rid", + "name": "test-name", + "domain": "test-domain", + "hp": 1, + "ext": "test-ext" + } + ], + "ver": "1.0", + "ext": "test-ext" + }, + "ext": "test-ext" + }, + "regs": { + "gdpr": 0 + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "10b1e33f-fddc-4621-a472-d7bff0529cbf", + "seatbid": [ + { + "bid": [ + { + "id": "1", + "impid": "1", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + { + "id": "1", + "impid": "2", + "price": 0.78740156, + "protocol": 0, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "attr": [], + "api": 0, + "mtype": 1, + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + } + ], + "seat": "2271" + } + ], + "cur": "USD", + "ext": { + "uss": 1 + } + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "1", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + }, + { + "bid": { + "id": "1", + "impid": "2", + "price": 0.78740156, + "mtype": 1, + "adm": "<html><h3>I am an ad</h3></html>", + "adomain": [ + "emetriq.com" + ], + "cid": "ay35w7m", + "crid": "id8tke3f", + "w": 300, + "h": 250, + "cat": [ + "IAB2", + "IAB2-3" + ] + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-204.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-204.json new file mode 100644 index 0000000000..d75a72db37 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-204.json @@ -0,0 +1,57 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org", + "publisher": { + "id": "123" + } + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-500.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-500.json new file mode 100644 index 0000000000..90f52ce01b --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/response-http-500.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org", + "publisher": { + "id": "123" + } + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code", + "comparison": "startswith" + }] +} \ No newline at end of file diff --git a/adapters/tadvertising_blis/tadvertising_blistest/supplemental/unsupported-media-type.json b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/unsupported-media-type.json new file mode 100644 index 0000000000..8751c015e4 --- /dev/null +++ b/adapters/tadvertising_blis/tadvertising_blistest/supplemental/unsupported-media-type.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-req", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.endpoint/", + "body": { + "id": "test-req", + "site": { + "page": "prebid.org", + "publisher": { + "id": "123" + } + }, + "imp": [{ + "id": "test-imp", + "banner": { + "format": [{ + "w": 300, + "h": 600 + }] + }, + "ext": { + "bidder": { + "publisherId": "123" + } + } + }] + }, + "impIDs":["test-imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-req", + "seatbid": [ + { + "seat": "None", + "bid": [ + { + "id": "1", + "impid": "testimp", + "price": 1.2, + "crid": "9999999", + "w": 320, + "h": 50, + "adomain": [ + "example.com" + ], + "cid": "999999", + "adm": "<a href=\"https://clickexample.com/\" target=\"_blank\"><img src=\"https://adserverexample.com/example.gif\" width=\"320\" height=\"50\" alt=\"\" /></a>", + "burl": "https://trackingexample.com/pixel?wp=${AUCTION_PRICE}", + "mtype": 6 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + ] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Failed to parse media type of impression ID \"testimp\"", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 630fbe348b..35619a799e 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -224,6 +224,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/startio" "github.com/prebid/prebid-server/v4/adapters/stroeerCore" "github.com/prebid/prebid-server/v4/adapters/taboola" + "github.com/prebid/prebid-server/v4/adapters/tadvertising_blis" "github.com/prebid/prebid-server/v4/adapters/tappx" "github.com/prebid/prebid-server/v4/adapters/teads" "github.com/prebid/prebid-server/v4/adapters/telaria" @@ -494,6 +495,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderStartIO: startio.Builder, openrtb_ext.BidderStroeerCore: stroeerCore.Builder, openrtb_ext.BidderTaboola: taboola.Builder, + openrtb_ext.BidderTAdvertisingBlis: tadvertising_blis.Builder, openrtb_ext.BidderTappx: tappx.Builder, openrtb_ext.BidderTeads: teads.Builder, openrtb_ext.BidderTelaria: telaria.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1b61ff724e..9b7d162f74 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -242,6 +242,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderStartIO, BidderStroeerCore, BidderTaboola, + BidderTAdvertisingBlis, BidderTappx, BidderTeads, BidderTelaria, @@ -616,6 +617,7 @@ const ( BidderStartIO BidderName = "startio" BidderStroeerCore BidderName = "stroeerCore" BidderTaboola BidderName = "taboola" + BidderTAdvertisingBlis BidderName = "tadvertising_blis" BidderTappx BidderName = "tappx" BidderTeads BidderName = "teads" BidderTelaria BidderName = "telaria" diff --git a/openrtb_ext/imp_tadvertisingblis.go b/openrtb_ext/imp_tadvertisingblis.go new file mode 100644 index 0000000000..dee8d26031 --- /dev/null +++ b/openrtb_ext/imp_tadvertisingblis.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtTadvertising struct { + PublisherId string `json:"publisherId"` +} diff --git a/static/bidder-info/tadvertising_blis.yaml b/static/bidder-info/tadvertising_blis.yaml new file mode 100644 index 0000000000..115a4f752b --- /dev/null +++ b/static/bidder-info/tadvertising_blis.yaml @@ -0,0 +1,21 @@ +endpoint: "https://prebid-blis.tads.xplosion.de/bid" +endpointCompression: gzip +geoscope: + - GLOBAL +maintainer: + email: dev@emetriq.com +gvlVendorID: 213 +modifyingVastXmlAllowed: true +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native \ No newline at end of file diff --git a/static/bidder-params/tadvertising_blis.json b/static/bidder-params/tadvertising_blis.json new file mode 100644 index 0000000000..1c1d893cf3 --- /dev/null +++ b/static/bidder-params/tadvertising_blis.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "T-Advertising-Blis Adapter Params", + "description": "A schema which validates params accepted by the T-Advertising-Blis adapter", + "type": "object", + + "properties": { + "publisherId": { + "type": "string", + "minLength": 1, + "maxLength": 32, + "description": "Unique ID of the publisher/supply partner provided by T-Advertising" + } + }, + + "required": ["publisherId"] +} \ No newline at end of file From 86b6961cfaf0cb6dbc96518e9d992a9fc9e186d8 Mon Sep 17 00:00:00 2001 From: Dmytro Shyrokov <shirokoffdima@gmail.com> Date: Tue, 12 May 2026 23:10:24 +0300 Subject: [PATCH 209/272] Adipolo: Add GVL Vendor ID (#4734) --- static/bidder-info/adipolo.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/bidder-info/adipolo.yaml b/static/bidder-info/adipolo.yaml index 0cf1ac3430..0189ca5ed3 100644 --- a/static/bidder-info/adipolo.yaml +++ b/static/bidder-info/adipolo.yaml @@ -2,10 +2,11 @@ aliasOf: xeworks endpoint: "http://rtb.adipolo.live?pid={{.SourceId}}&host={{.Host}}&pbs=1" maintainer: email: "smart@adipolo.com" +gvlVendorID: 1456 userSync: iframe: url: "https://sync.adipolo.live/static/adisync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&cb={{.RedirectURL}}" userMacro: $UID redirect: url: "https://sync.adipolo.live/psync?t=s&e=0&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&cb={{.RedirectURL}}" - userMacro: "$UID" \ No newline at end of file + userMacro: "$UID" From ad2fd781f61d1b9a1013ae97902840e8e552e395 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic <filip.stamenkovic@showheroes-group.com> Date: Wed, 13 May 2026 04:49:16 +0200 Subject: [PATCH 210/272] Showheroes: Enable gzip compression (#4730) --- static/bidder-info/showheroes.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/showheroes.yaml b/static/bidder-info/showheroes.yaml index 29296ecd91..0586f34ca4 100644 --- a/static/bidder-info/showheroes.yaml +++ b/static/bidder-info/showheroes.yaml @@ -2,6 +2,7 @@ endpoint: "https://ads.viralize.tv/openrtb2/auction/" maintainer: email: tech@showheroes.com gvlVendorID: 111 +endpointCompression: gzip openrtb: version: 2.6 capabilities: From 5be4149afaf832036844939934ad6484b5ae3dbb Mon Sep 17 00:00:00 2001 From: Denis Logachov <ckbo3hrk@gmail.com> Date: Wed, 13 May 2026 05:58:48 +0300 Subject: [PATCH 211/272] New Adapter: Waardex - Adkernel Alias (#4645) --- static/bidder-info/waardex_ak.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/bidder-info/waardex_ak.yaml diff --git a/static/bidder-info/waardex_ak.yaml b/static/bidder-info/waardex_ak.yaml new file mode 100644 index 0000000000..36dce9a134 --- /dev/null +++ b/static/bidder-info/waardex_ak.yaml @@ -0,0 +1,8 @@ +aliasOf: adkernel +userSync: + redirect: + url: "https://sync.adkernel.com/user-sync?t=image&zone=313534&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" + iframe: + url: "https://sync.adkernel.com/user-sync?t=iframe&zone=313534&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" \ No newline at end of file From d546331fc39c3b726e3ffe7b376b560060688fb4 Mon Sep 17 00:00:00 2001 From: Rafael Taveira <103446145+rafataveira@users.noreply.github.com> Date: Tue, 12 May 2026 22:33:17 -0500 Subject: [PATCH 212/272] Nativo: Add optional placementId param & Prebid Renderer in response (#4679) --- adapters/nativo/nativo.go | 68 ++++- adapters/nativo/nativo_test.go | 246 ++++++++++++++++++ .../nativotest/exemplary/banner-app.json | 60 ++++- .../exemplary/banner-web-no-placementid.json | 121 +++++++++ .../banner-web-string-placementid.json | 125 +++++++++ .../nativotest/exemplary/banner-web.json | 10 + .../nativotest/exemplary/native-app.json | 60 ++++- .../nativotest/exemplary/native-web.json | 10 + .../nativotest/exemplary/video-app.json | 60 ++++- .../nativotest/exemplary/video-web.json | 10 + ...-different-impID-response-from-nativo.json | 10 +- .../400-response-from-nativo.json | 8 +- .../500-response-from-nativo.json | 8 +- .../bid-type-fallback-invalid-type.json | 91 +++++++ .../bid-type-fallback-native.json | 92 +++++++ .../bid-type-fallback-success.json | 102 ++++++++ .../supplemental/bid-type-fallback-video.json | 96 +++++++ .../supplemental/malformed-response-body.json | 62 +++++ .../nativo-renderer-in-request.json | 116 +++++++++ adapters/nativo/params_test.go | 44 ++++ openrtb_ext/imp_nativo.go | 7 + static/bidder-params/nativo.json | 7 +- 22 files changed, 1381 insertions(+), 32 deletions(-) create mode 100644 adapters/nativo/nativotest/exemplary/banner-web-no-placementid.json create mode 100644 adapters/nativo/nativotest/exemplary/banner-web-string-placementid.json create mode 100644 adapters/nativo/nativotest/supplemental/bid-type-fallback-invalid-type.json create mode 100644 adapters/nativo/nativotest/supplemental/bid-type-fallback-native.json create mode 100644 adapters/nativo/nativotest/supplemental/bid-type-fallback-success.json create mode 100644 adapters/nativo/nativotest/supplemental/bid-type-fallback-video.json create mode 100644 adapters/nativo/nativotest/supplemental/malformed-response-body.json create mode 100644 adapters/nativo/nativotest/supplemental/nativo-renderer-in-request.json create mode 100644 adapters/nativo/params_test.go create mode 100644 openrtb_ext/imp_nativo.go diff --git a/adapters/nativo/nativo.go b/adapters/nativo/nativo.go index ab84e01575..b06020a830 100644 --- a/adapters/nativo/nativo.go +++ b/adapters/nativo/nativo.go @@ -1,14 +1,16 @@ package nativo import ( - "encoding/json" "fmt" "net/http" + "strings" "github.com/prebid/openrtb/v20/openrtb2" "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" ) type adapter struct { @@ -24,7 +26,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co } func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - requestJSON, err := json.Marshal(request) + requestJSON, err := jsonutil.Marshal(request) if err != nil { return nil, []error{err} } @@ -54,32 +56,80 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapte var bidResp openrtb2.BidResponse - if err := json.Unmarshal(response.Body, &bidResp); err != nil { - return nil, []error{err} + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} } bidResponse := adapters.NewBidderResponse() + // Get the ext from the request + var extReq openrtb_ext.ExtRequest + if len(request.Ext) > 0 { + _ = jsonutil.Unmarshal(request.Ext, &extReq) + } + var errs []error - for _, seatBid := range bidResp.SeatBid { - for i := range seatBid.Bid { - bidType, err := getMediaTypeForImp(seatBid.Bid[i].ImpID, request.Imp) + for seatBidIndex := range bidResp.SeatBid { + seatBid := bidResp.SeatBid[seatBidIndex] + for bidIndex := range seatBid.Bid { + bid := seatBid.Bid[bidIndex] + bidType, err := getMediaTypeForImp(bid.ImpID, request.Imp) + if err != nil { + // Fallback needed in some cases with Prebid SDK + bidType, err = getMediaTypeForBid(bid) + } if err != nil { errs = append(errs, err) continue } b := &adapters.TypedBid{ - Bid: &seatBid.Bid[i], + Bid: &seatBid.Bid[bidIndex], BidType: bidType, + BidMeta: getRendererMeta(&extReq), } - bidResponse.Bids = append(bidResponse.Bids, b) } } return bidResponse, errs } +// Attempt to set NativoRenderer as the meta renderer if it exists in the request ext +func getRendererMeta(ext *openrtb_ext.ExtRequest) *openrtb_ext.ExtBidPrebidMeta { + if ext == nil || ext.Prebid.Sdk == nil { + return nil + } + const rendererName = "NativoRenderer" + for i := range ext.Prebid.Sdk.Renderers { + renderer := &ext.Prebid.Sdk.Renderers[i] + if strings.EqualFold(renderer.Name, rendererName) { + return &openrtb_ext.ExtBidPrebidMeta{ + RendererName: renderer.Name, + RendererVersion: renderer.Version, + } + } + } + return nil +} + +// Get media type from bid response +func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil && bidExt.Prebid != nil { + return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) + } + } + + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID), + } +} + +// Get media type from bid request func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { for _, imp := range imps { if imp.ID == impID { diff --git a/adapters/nativo/nativo_test.go b/adapters/nativo/nativo_test.go index 6318bc0aea..3877bb0065 100644 --- a/adapters/nativo/nativo_test.go +++ b/adapters/nativo/nativo_test.go @@ -1,11 +1,16 @@ package nativo import ( + "encoding/json" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" "github.com/prebid/prebid-server/v4/adapters/adapterstest" "github.com/prebid/prebid-server/v4/config" "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestBidderNativo(t *testing.T) { @@ -19,3 +24,244 @@ func TestBidderNativo(t *testing.T) { adapterstest.RunJSONBidderTest(t, "nativotest", bidder) } + +func TestGetRendererMeta(t *testing.T) { + tests := []struct { + description string + ext *openrtb_ext.ExtRequest + expected *openrtb_ext.ExtBidPrebidMeta + }{ + { + description: "nil ext returns nil", + ext: nil, + expected: nil, + }, + { + description: "nil sdk returns nil", + ext: &openrtb_ext.ExtRequest{}, + expected: nil, + }, + { + description: "empty renderers returns nil", + ext: &openrtb_ext.ExtRequest{ + Prebid: openrtb_ext.ExtRequestPrebid{ + Sdk: &openrtb_ext.ExtRequestSdk{}, + }, + }, + expected: nil, + }, + { + description: "NativoRenderer found returns meta with name and version", + ext: &openrtb_ext.ExtRequest{ + Prebid: openrtb_ext.ExtRequestPrebid{ + Sdk: &openrtb_ext.ExtRequestSdk{ + Renderers: []openrtb_ext.ExtRequestSdkRenderer{ + {Name: "NativoRenderer", Version: "1.0"}, + }, + }, + }, + }, + expected: &openrtb_ext.ExtBidPrebidMeta{ + RendererName: "NativoRenderer", + RendererVersion: "1.0", + }, + }, + { + description: "NativoRenderer matched case-insensitively", + ext: &openrtb_ext.ExtRequest{ + Prebid: openrtb_ext.ExtRequestPrebid{ + Sdk: &openrtb_ext.ExtRequestSdk{ + Renderers: []openrtb_ext.ExtRequestSdkRenderer{ + {Name: "nativorenderer", Version: "2.0"}, + }, + }, + }, + }, + expected: &openrtb_ext.ExtBidPrebidMeta{ + RendererName: "nativorenderer", + RendererVersion: "2.0", + }, + }, + { + description: "non-NativoRenderer returns nil", + ext: &openrtb_ext.ExtRequest{ + Prebid: openrtb_ext.ExtRequestPrebid{ + Sdk: &openrtb_ext.ExtRequestSdk{ + Renderers: []openrtb_ext.ExtRequestSdkRenderer{ + {Name: "OtherRenderer", Version: "1.0"}, + }, + }, + }, + }, + expected: nil, + }, + { + description: "NativoRenderer found among multiple renderers", + ext: &openrtb_ext.ExtRequest{ + Prebid: openrtb_ext.ExtRequestPrebid{ + Sdk: &openrtb_ext.ExtRequestSdk{ + Renderers: []openrtb_ext.ExtRequestSdkRenderer{ + {Name: "OtherRenderer", Version: "1.0"}, + {Name: "NativoRenderer", Version: "3.0"}, + }, + }, + }, + }, + expected: &openrtb_ext.ExtBidPrebidMeta{ + RendererName: "NativoRenderer", + RendererVersion: "3.0", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + result := getRendererMeta(test.ext) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestGetMediaTypeForBid(t *testing.T) { + tests := []struct { + description string + bid openrtb2.Bid + expectedType openrtb_ext.BidType + hasError bool + }{ + { + description: "nil ext returns error", + bid: openrtb2.Bid{ImpID: "test-imp"}, + hasError: true, + }, + { + description: "invalid ext JSON returns error", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`invalid`)}, + hasError: true, + }, + { + description: "ext without prebid field returns error", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`{"other":"data"}`)}, + hasError: true, + }, + { + description: "valid banner type", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`{"prebid":{"type":"banner"}}`)}, + expectedType: openrtb_ext.BidTypeBanner, + }, + { + description: "valid native type", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`{"prebid":{"type":"native"}}`)}, + expectedType: openrtb_ext.BidTypeNative, + }, + { + description: "valid video type", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`{"prebid":{"type":"video"}}`)}, + expectedType: openrtb_ext.BidTypeVideo, + }, + { + description: "unknown bid type string returns error", + bid: openrtb2.Bid{ImpID: "test-imp", Ext: json.RawMessage(`{"prebid":{"type":"unknown"}}`)}, + hasError: true, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + result, err := getMediaTypeForBid(test.bid) + if test.hasError { + assert.Error(t, err) + assert.Empty(t, result) + } else { + assert.NoError(t, err) + assert.Equal(t, test.expectedType, result) + } + }) + } +} + +func TestGetMediaTypeForImp(t *testing.T) { + tests := []struct { + description string + impID string + imps []openrtb2.Imp + expectedType openrtb_ext.BidType + hasError bool + }{ + { + description: "banner imp", + impID: "test-imp", + imps: []openrtb2.Imp{{ID: "test-imp", Banner: &openrtb2.Banner{}}}, + expectedType: openrtb_ext.BidTypeBanner, + }, + { + description: "video imp", + impID: "test-imp", + imps: []openrtb2.Imp{{ID: "test-imp", Video: &openrtb2.Video{}}}, + expectedType: openrtb_ext.BidTypeVideo, + }, + { + description: "native imp", + impID: "test-imp", + imps: []openrtb2.Imp{{ID: "test-imp", Native: &openrtb2.Native{}}}, + expectedType: openrtb_ext.BidTypeNative, + }, + { + description: "imp not found returns error", + impID: "unknown-imp", + imps: []openrtb2.Imp{{ID: "test-imp", Banner: &openrtb2.Banner{}}}, + hasError: true, + }, + { + description: "imp found but no media type set returns error", + impID: "test-imp", + imps: []openrtb2.Imp{{ID: "test-imp"}}, + hasError: true, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + result, err := getMediaTypeForImp(test.impID, test.imps) + if test.hasError { + assert.Error(t, err) + assert.Empty(t, result) + } else { + assert.NoError(t, err) + assert.Equal(t, test.expectedType, result) + } + }) + } +} + +func TestMakeBidsNativoRenderer(t *testing.T) { + bidder := &adapter{endpoint: "https://foo.io/?src=prebid"} + + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{ + {ID: "test-imp", Banner: &openrtb2.Banner{}}, + }, + Ext: json.RawMessage(`{"prebid":{"sdk":{"renderers":[{"name":"NativoRenderer","version":"1.0.0"}]}}}`), + } + + response := &adapters.ResponseData{ + StatusCode: 200, + Body: json.RawMessage(`{ + "id": "test-response-id", + "seatbid": [{"bid": [{"id": "bid-id", "impid": "test-imp", "price": 3.5}], "seat": "nativo"}], + "cur": "USD" + }`), + } + + bidderResp, errs := bidder.MakeBids(request, nil, response) + + require.Empty(t, errs) + require.Len(t, bidderResp.Bids, 1) + + bid := bidderResp.Bids[0] + assert.Equal(t, openrtb_ext.BidTypeBanner, bid.BidType) + require.NotNil(t, bid.BidMeta) + assert.Equal(t, "NativoRenderer", bid.BidMeta.RendererName) + assert.Equal(t, "1.0.0", bid.BidMeta.RendererVersion) +} diff --git a/adapters/nativo/nativotest/exemplary/banner-app.json b/adapters/nativo/nativotest/exemplary/banner-app.json index 738d01bd9a..29280cbc05 100644 --- a/adapters/nativo/nativotest/exemplary/banner-app.json +++ b/adapters/nativo/nativotest/exemplary/banner-app.json @@ -30,9 +30,26 @@ "banner": { "w": 320, "h": 50 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } - ] + ], + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "httpCalls": [ { @@ -53,7 +70,12 @@ "w": 320, "h": 50 }, - "tagid": "ogTAGID" + "tagid": "ogTAGID", + "ext": { + "bidder": { + "placementId": 12345678 + } + } } ], "app": { @@ -71,7 +93,19 @@ "user": { "buyeruid": "awesome-user" }, - "tmax": 1000 + "tmax": 1000, + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "impIDs":["some-impression-id"] }, @@ -92,7 +126,15 @@ ], "crid": "20", "w": 320, - "h": 50 + "h": 50, + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } } ], "seat": "nativo" @@ -123,7 +165,15 @@ ], "crid": "20", "w": 320, - "h": 50 + "h": 50, + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } }, "type": "banner" } diff --git a/adapters/nativo/nativotest/exemplary/banner-web-no-placementid.json b/adapters/nativo/nativotest/exemplary/banner-web-no-placementid.json new file mode 100644 index 0000000000..d4c3d38a00 --- /dev/null +++ b/adapters/nativo/nativotest/exemplary/banner-web-no-placementid.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": {} + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": ["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativo/nativotest/exemplary/banner-web-string-placementid.json b/adapters/nativo/nativotest/exemplary/banner-web-string-placementid.json new file mode 100644 index 0000000000..a26662fed2 --- /dev/null +++ b/adapters/nativo/nativotest/exemplary/banner-web-string-placementid.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "placementId": "12345678" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "placementId": "12345678" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + }, + "impIDs": ["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "crid": "20", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativo/nativotest/exemplary/banner-web.json b/adapters/nativo/nativotest/exemplary/banner-web.json index 58af89b202..ce67bbd15f 100644 --- a/adapters/nativo/nativotest/exemplary/banner-web.json +++ b/adapters/nativo/nativotest/exemplary/banner-web.json @@ -24,6 +24,11 @@ "banner": { "w":320, "h":50 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ] @@ -47,6 +52,11 @@ "banner": { "w":320, "h":50 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ], diff --git a/adapters/nativo/nativotest/exemplary/native-app.json b/adapters/nativo/nativotest/exemplary/native-app.json index 5f038958b7..5f3e5a730d 100644 --- a/adapters/nativo/nativotest/exemplary/native-app.json +++ b/adapters/nativo/nativotest/exemplary/native-app.json @@ -30,9 +30,26 @@ "native": { "ver":"1.1", "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } - ] + ], + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "httpCalls": [ { @@ -53,7 +70,12 @@ "ver":"1.1", "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" }, - "tagid": "ogTAGID" + "tagid": "ogTAGID", + "ext": { + "bidder": { + "placementId": 12345678 + } + } } ], "app": { @@ -71,7 +93,19 @@ "user": { "buyeruid": "awesome-user" }, - "tmax": 1000 + "tmax": 1000, + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "impIDs":["some-impression-id"] }, @@ -90,7 +124,15 @@ "adomain": [ "awesome.com" ], - "crid": "20" + "crid": "20", + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } } ], "seat": "nativo" @@ -119,7 +161,15 @@ "crid": "20", "adomain": [ "awesome.com" - ] + ], + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } }, "type": "native" } diff --git a/adapters/nativo/nativotest/exemplary/native-web.json b/adapters/nativo/nativotest/exemplary/native-web.json index 598dc2abfc..98e0ca38df 100644 --- a/adapters/nativo/nativotest/exemplary/native-web.json +++ b/adapters/nativo/nativotest/exemplary/native-web.json @@ -24,6 +24,11 @@ "native": { "ver":"1.1", "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ] @@ -47,6 +52,11 @@ "native": { "ver":"1.1", "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ], diff --git a/adapters/nativo/nativotest/exemplary/video-app.json b/adapters/nativo/nativotest/exemplary/video-app.json index 596bf9bcaf..2a478e2526 100644 --- a/adapters/nativo/nativotest/exemplary/video-app.json +++ b/adapters/nativo/nativotest/exemplary/video-app.json @@ -35,9 +35,26 @@ "h": 480, "minduration": 120, "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } - ] + ], + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "httpCalls": [ { @@ -63,7 +80,12 @@ "w": 640, "h": 480 }, - "tagid": "ogTAGID" + "tagid": "ogTAGID", + "ext": { + "bidder": { + "placementId": 12345678 + } + } } ], "app": { @@ -81,7 +103,19 @@ "user": { "buyeruid": "awesome-user" }, - "tmax": 1000 + "tmax": 1000, + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } }, "impIDs":["some-impression-id"] }, @@ -102,7 +136,15 @@ ], "crid": "20", "w": 1280, - "h": 720 + "h": 720, + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } } ], "seat": "nativo" @@ -133,7 +175,15 @@ "awesome.com" ], "w": 1280, - "h": 720 + "h": 720, + "ext": { + "prebid": { + "meta": { + "rendererName": "NativoRenderer", + "rendererVersion": "1.0.0" + } + } + } }, "type": "video" } diff --git a/adapters/nativo/nativotest/exemplary/video-web.json b/adapters/nativo/nativotest/exemplary/video-web.json index 12e185ca15..a1043b2136 100644 --- a/adapters/nativo/nativotest/exemplary/video-web.json +++ b/adapters/nativo/nativotest/exemplary/video-web.json @@ -29,6 +29,11 @@ "h": 480, "minduration": 120, "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ] @@ -57,6 +62,11 @@ "maxduration": 150, "w": 640, "h": 480 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } } } ], diff --git a/adapters/nativo/nativotest/supplemental/200-different-impID-response-from-nativo.json b/adapters/nativo/nativotest/supplemental/200-different-impID-response-from-nativo.json index 320d7f5e1b..96e4b3e875 100755 --- a/adapters/nativo/nativotest/supplemental/200-different-impID-response-from-nativo.json +++ b/adapters/nativo/nativotest/supplemental/200-different-impID-response-from-nativo.json @@ -13,7 +13,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": "12345678" + } } } ] @@ -36,7 +38,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": "12345678" + } } } ] @@ -74,7 +78,7 @@ ], "expectedMakeBidsErrors": [ { - "value": "Unrecognized impression type in response from nativo: nativo-id-2", + "value": "Failed to parse impression \"nativo-id-2\" mediatype", "comparison": "literal" } ] diff --git a/adapters/nativo/nativotest/supplemental/400-response-from-nativo.json b/adapters/nativo/nativotest/supplemental/400-response-from-nativo.json index f5ebb6024c..342ad1a243 100755 --- a/adapters/nativo/nativotest/supplemental/400-response-from-nativo.json +++ b/adapters/nativo/nativotest/supplemental/400-response-from-nativo.json @@ -13,7 +13,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": 12345678 + } } } ] @@ -36,7 +38,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": 12345678 + } } } ] diff --git a/adapters/nativo/nativotest/supplemental/500-response-from-nativo.json b/adapters/nativo/nativotest/supplemental/500-response-from-nativo.json index cc58f18ece..c111cf3edd 100755 --- a/adapters/nativo/nativotest/supplemental/500-response-from-nativo.json +++ b/adapters/nativo/nativotest/supplemental/500-response-from-nativo.json @@ -13,7 +13,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": 12345678 + } } } ] @@ -36,7 +38,9 @@ ] }, "ext": { - "bidder": {} + "bidder": { + "placementId": 12345678 + } } } ] diff --git a/adapters/nativo/nativotest/supplemental/bid-type-fallback-invalid-type.json b/adapters/nativo/nativotest/supplemental/bid-type-fallback-invalid-type.json new file mode 100644 index 0000000000..2a6c36c019 --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/bid-type-fallback-invalid-type.json @@ -0,0 +1,91 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 50, + "ext": { + "prebid": { + "type": "unknown" + } + } + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "invalid BidType: unknown", + "comparison": "literal" + } + ] +} diff --git a/adapters/nativo/nativotest/supplemental/bid-type-fallback-native.json b/adapters/nativo/nativotest/supplemental/bid-type-fallback-native.json new file mode 100644 index 0000000000..3eec53f1bc --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/bid-type-fallback-native.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/nativo/nativotest/supplemental/bid-type-fallback-success.json b/adapters/nativo/nativotest/supplemental/bid-type-fallback-success.json new file mode 100644 index 0000000000..286fa30ae7 --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/bid-type-fallback-success.json @@ -0,0 +1,102 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 50, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativo/nativotest/supplemental/bid-type-fallback-video.json b/adapters/nativo/nativotest/supplemental/bid-type-fallback-video.json new file mode 100644 index 0000000000..9bbab6b643 --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/bid-type-fallback-video.json @@ -0,0 +1,96 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 5.0, + "adm": "awesome-video-markup", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "nativo-id-2", + "price": 5.0, + "adm": "awesome-video-markup", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/nativo/nativotest/supplemental/malformed-response-body.json b/adapters/nativo/nativotest/supplemental/malformed-response-body.json new file mode 100644 index 0000000000..c49a72cb1e --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/malformed-response-body.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ] + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": "invalid-body" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/nativo/nativotest/supplemental/nativo-renderer-in-request.json b/adapters/nativo/nativotest/supplemental/nativo-renderer-in-request.json new file mode 100644 index 0000000000..4d03e79af2 --- /dev/null +++ b/adapters/nativo/nativotest/supplemental/nativo-renderer-in-request.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ], + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://foo.io/?src=prebid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "nativo-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placementId": 12345678 + } + } + } + ], + "ext": { + "prebid": { + "sdk": { + "renderers": [ + { + "name": "NativoRenderer", + "version": "1.0.0" + } + ] + } + } + } + }, + "impIDs": ["nativo-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id", + "impid": "nativo-id", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 250 + } + ], + "seat": "nativo" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id", + "impid": "nativo-id", + "price": 3.5, + "adm": "awesome-markup", + "w": 300, + "h": 250 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/nativo/params_test.go b/adapters/nativo/params_test.go new file mode 100644 index 0000000000..8d8cc8a4a8 --- /dev/null +++ b/adapters/nativo/params_test.go @@ -0,0 +1,44 @@ +package nativo + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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.BidderNativo, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected valid 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.BidderNativo, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId": "12345678"}`, + `{"placementId": 12345678}`, + `{}`, +} + +var invalidParams = []string{ + `{"placementId": false}`, +} diff --git a/openrtb_ext/imp_nativo.go b/openrtb_ext/imp_nativo.go new file mode 100644 index 0000000000..b4623bc5e8 --- /dev/null +++ b/openrtb_ext/imp_nativo.go @@ -0,0 +1,7 @@ +package openrtb_ext + +import "github.com/prebid/prebid-server/v4/util/jsonutil" + +type ImpExtNativo struct { + PlacementID jsonutil.StringInt `json:"placementId"` +} diff --git a/static/bidder-params/nativo.json b/static/bidder-params/nativo.json index 0a8139a083..fbe4685b55 100644 --- a/static/bidder-params/nativo.json +++ b/static/bidder-params/nativo.json @@ -3,5 +3,10 @@ "title": "Nativo Adapter Params", "description": "A schema which validates params accepted by the Nativo adapter", "type": "object", - "properties": {} + "properties": { + "placementId": { + "type": ["integer", "string"], + "description": "Placement ID" + } + } } \ No newline at end of file From d980070d67a62025d82cc121d40e110657ba6759 Mon Sep 17 00:00:00 2001 From: cortex-tech <dev@cortextech.it> Date: Wed, 13 May 2026 06:49:03 +0300 Subject: [PATCH 213/272] New Adapter: Cortex (#4755) Co-authored-by: Cortex Dev <dev@cortexch.it> --- static/bidder-info/cortex.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 static/bidder-info/cortex.yaml diff --git a/static/bidder-info/cortex.yaml b/static/bidder-info/cortex.yaml new file mode 100644 index 0000000000..52d811cbc9 --- /dev/null +++ b/static/bidder-info/cortex.yaml @@ -0,0 +1,22 @@ +aliasOf: "teqblaze" +endpoint: "https://eu.targetadserver.com/pserver" +maintainer: + email: "dev@cortextech.it" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://sync.targetadserver.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://sync.targetadserver.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 4f77129830789234fe4493e5b4595bbd06504450 Mon Sep 17 00:00:00 2001 From: Volokha Alexandr <volokha.alexandr@gmail.com> Date: Wed, 13 May 2026 04:02:20 +0000 Subject: [PATCH 214/272] New Adapter: RTBStack (#4685) Co-authored-by: Volokha <avolokha@admixer.ua> --- adapters/rtbstack/params_test.go | 57 ++++ adapters/rtbstack/rtbstack.go | 269 ++++++++++++++++++ adapters/rtbstack/rtbstack_test.go | 29 ++ .../rtbstacktest/exemplary/app-audio.json | 162 +++++++++++ .../rtbstacktest/exemplary/app-banner.json | 162 +++++++++++ .../rtbstacktest/exemplary/app-native.json | 146 ++++++++++ .../rtbstacktest/exemplary/app-video.json | 188 ++++++++++++ .../exemplary/multi-route-grouping.json | 235 +++++++++++++++ .../exemplary/multi-route-same.json | 162 +++++++++++ .../exemplary/no-currency-in-response.json | 99 +++++++ .../exemplary/optional-params.json | 228 +++++++++++++++ .../rtbstacktest/exemplary/site-audio.json | 158 ++++++++++ .../rtbstacktest/exemplary/site-banner.json | 229 +++++++++++++++ .../exemplary/site-domain-empty-mutation.json | 70 +++++ .../exemplary/site-domain-fallback.json | 100 +++++++ .../exemplary/site-domain-mutation.json | 71 +++++ .../rtbstacktest/exemplary/site-native.json | 148 ++++++++++ .../exemplary/site-region-eu.json | 107 +++++++ .../exemplary/site-region-sg.json | 113 ++++++++ .../rtbstacktest/exemplary/site-video.json | 184 ++++++++++++ .../supplemental/bad-bidder-ext.json | 27 ++ .../rtbstacktest/supplemental/bad-imp.json | 29 ++ .../rtbstacktest/supplemental/bad-mtype.json | 94 ++++++ .../supplemental/bad-response.json | 69 +++++ .../bad-route-invalid-region.json | 30 ++ .../bad-route-missing-params.json | 30 ++ .../multi-route-partial-failure.json | 123 ++++++++ .../rtbstacktest/supplemental/no-imps.json | 17 ++ .../rtbstacktest/supplemental/status-204.json | 71 +++++ .../rtbstacktest/supplemental/status-400.json | 77 +++++ .../supplemental/two-imps-one-is-bad.json | 89 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_rtbstack.go | 7 + static/bidder-info/rtbstack.yaml | 19 ++ static/bidder-params/rtbstack.json | 24 ++ 36 files changed, 3627 insertions(+) create mode 100644 adapters/rtbstack/params_test.go 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/multi-route-grouping.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/multi-route-same.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.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-fallback.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-region-eu.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json create mode 100644 adapters/rtbstack/rtbstacktest/exemplary/site-video.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-bidder-ext.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/bad-response.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 create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json create mode 100644 adapters/rtbstack/rtbstacktest/supplemental/no-imps.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/params_test.go b/adapters/rtbstack/params_test.go new file mode 100644 index 0000000000..087302decb --- /dev/null +++ b/adapters/rtbstack/params_test.go @@ -0,0 +1,57 @@ +package rtbstack + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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 new file mode 100644 index 0000000000..5b5b73f0a3 --- /dev/null +++ b/adapters/rtbstack/rtbstack.go @@ -0,0 +1,269 @@ +package rtbstack + +import ( + "fmt" + "net/http" + "net/url" + "strings" + "text/template" + + "github.com/prebid/openrtb/v20/openrtb2" + "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 { + endpoint *template.Template +} + +// 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 { + CustomParams map[string]interface{} `json:"customParams,omitempty"` +} + +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: tpl, + } + 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 + impsByRoute := make(map[string][]*impCtx) + var routeOrder []string + + for i := range request.Imp { + imp, ext, err := preprocessImp(request.Imp[i]) + if err != nil { + errs = append(errs, err) + continue + } + + 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(routeOrder) == 0 { + return nil, errs + } + + var newSite *openrtb2.Site + if request.Site != nil && request.Site.Domain == "" { + siteCopy := *request.Site + pageURL, parseErr := url.Parse(request.Site.Page) + if parseErr == nil && pageURL.Hostname() != "" { + siteCopy.Domain = pageURL.Hostname() + } else { + siteCopy.Domain = request.Site.Page + } + newSite = &siteCopy + } + + 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 + } + + return requests, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + if len(bidResp.SeatBid) == 0 { + return nil, nil + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) + + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } + + var bidErrs []error + for _, sb := range bidResp.SeatBid { + 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: &sb.Bid[i], + BidType: bidType, + }) + } + } + return bidResponse, bidErrs +} + +var validRegions = map[string]bool{"us": true, "eu": true, "sg": true} + +func (a *adapter) buildEndpointURL(ext *openrtb_ext.ExtImpRTBStack) (string, error) { + routeURL, err := url.Parse(ext.Route) + if err != nil { + return "", &errortypes.BadInput{Message: fmt.Sprintf("invalid route URL: %v", err)} + } + + region, err := extractRegion(routeURL.Hostname()) + if err != nil { + return "", err + } + + 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"} + } + + params := macros.EndpointTemplateParams{ + Region: region, + SspID: ssp, + ZoneID: endpoint, + PartnerId: client, + } + + 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, +) (openrtb2.Imp, *openrtb_ext.ExtImpRTBStack, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return imp, nil, &errortypes.BadInput{Message: err.Error()} + } + + var impExt openrtb_ext.ExtImpRTBStack + if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + return imp, nil, &errortypes.BadInput{ + Message: "Wrong RTBStack bidder ext", + } + } + + imp.TagID = impExt.TagId + + newExt := extImpRTBStack{ + CustomParams: impExt.CustomParams, + } + + newImpExtForRTBStack, err := jsonutil.Marshal(newExt) + if err != nil { + return imp, nil, &errortypes.BadInput{Message: err.Error()} + } + imp.Ext = newImpExtForRTBStack + + return imp, &impExt, nil +} + +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), + } + } +} diff --git a/adapters/rtbstack/rtbstack_test.go b/adapters/rtbstack/rtbstack_test.go new file mode 100644 index 0000000000..a28237d4ca --- /dev/null +++ b/adapters/rtbstack/rtbstack_test.go @@ -0,0 +1,29 @@ +package rtbstack + +import ( + "testing" + + "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) { + bidder, buildErr := Builder(openrtb_ext.BidderRTBStack, config.Adapter{ + 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) + } + + 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/app-audio.json b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json new file mode 100644 index 0000000000..437343b056 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-audio.json @@ -0,0 +1,162 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-app-audio-long", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 15, + "maxduration": 60 + }, + "ext": { + "bidder": { + "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": {} + } + } + } + ] + }, + "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" + }, + "imp": [ + { + "id": "imp-app-audio-short", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 5, + "maxduration": 30 + }, + "tagid": "app-audio-short", + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-app-audio-long", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 15, + "maxduration": 60 + }, + "tagid": "app-audio-long", + "ext": {} + } + ] + }, + "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": "<audio src='short.mp3'></audio>", + "crid": "crid-app-audio-short-1", + "mtype": 3 + }, + { + "id": "bid-app-audio-long-1", + "impid": "imp-app-audio-long", + "price": 1.25, + "adm": "<audio src='long.mp3'></audio>", + "crid": "crid-app-audio-long-1", + "mtype": 3 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-audio-short-1", + "impid": "imp-app-audio-short", + "price": 0.75, + "adm": "<audio src='short.mp3'></audio>", + "crid": "crid-app-audio-short-1", + "mtype": 3 + }, + "type": "audio" + }, + { + "bid": { + "id": "bid-app-audio-long-1", + "impid": "imp-app-audio-long", + "price": 1.25, + "adm": "<audio src='long.mp3'></audio>", + "crid": "crid-app-audio-long-1", + "mtype": 3 + }, + "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 0000000000..1072a3946b --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-banner.json @@ -0,0 +1,162 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-app-large", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "app-large", + "customParams": {} + } + } + } + ] + }, + "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" + }, + "imp": [ + { + "id": "imp-app-basic", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "tagid": "app-basic", + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-app-large", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "app-large", + "ext": {} + } + ] + }, + "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": "<div>App Banner 320x50</div>", + "crid": "crid-app-basic-1", + "mtype": 1 + }, + { + "id": "bid-app-large-1", + "impid": "imp-app-large", + "price": 1.5, + "adm": "<div>App Banner 728x90</div>", + "crid": "crid-app-large-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-basic-1", + "impid": "imp-app-basic", + "price": 0.95, + "adm": "<div>App Banner 320x50</div>", + "crid": "crid-app-basic-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-app-large-1", + "impid": "imp-app-large", + "price": 1.5, + "adm": "<div>App Banner 728x90</div>", + "crid": "crid-app-large-1", + "mtype": 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 0000000000..af5549ff6c --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-native.json @@ -0,0 +1,146 @@ +{ + "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": { + "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" + } + } + } + }, + { + "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": { + "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": {} + } + } + } + ] + }, + "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" + }, + "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": { + "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": {} + } + ] + }, + "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", + "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", + "mtype": 4 + } + ] + } + ], + "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", + "mtype": 4 + }, + "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", + "mtype": 4 + }, + "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 0000000000..c2d5b4e6bc --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/app-video.json @@ -0,0 +1,188 @@ +{ + "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": { + "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" + } + } + } + }, + { + "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": { + "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": {} + } + } + } + ] + }, + "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" + }, + "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": { + "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": {} + } + ] + }, + "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": "<VAST version='3.0'>App Small Video Ad</VAST>", + "crid": "crid-app-video-small-1", + "mtype": 2 + }, + { + "id": "bid-app-video-large-1", + "impid": "imp-app-video-large", + "price": 5.5, + "adm": "<VAST version='3.0'>App Large Video Ad</VAST>", + "crid": "crid-app-video-large-1", + "mtype": 2 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-app-video-small-1", + "impid": "imp-app-video-small", + "price": 3.0, + "adm": "<VAST version='3.0'>App Small Video Ad</VAST>", + "crid": "crid-app-video-small-1", + "mtype": 2 + }, + "type": "video" + }, + { + "bid": { + "id": "bid-app-video-large-1", + "impid": "imp-app-video-large", + "price": 5.5, + "adm": "<VAST version='3.0'>App Large Video Ad</VAST>", + "crid": "crid-app-video-large-1", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} 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 0000000000..543b99815e --- /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": "<div>A1</div>", + "crid": "crid-a-1", + "mtype": 1 + }, + { + "id": "bid-a-2", + "impid": "imp-route-a-2", + "price": 2.5, + "adm": "<div>A2</div>", + "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": "<div>B1</div>", + "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": "<div>A1</div>", + "crid": "crid-a-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-a-2", + "impid": "imp-route-a-2", + "price": 2.5, + "adm": "<div>A2</div>", + "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": "<div>B1</div>", + "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 0000000000..a419ed2bcc --- /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": "<div>1</div>", + "crid": "crid-1", + "mtype": 1 + }, + { + "id": "bid-same-2", + "impid": "imp-same-2", + "price": 1.20, + "adm": "<div>2</div>", + "crid": "crid-2", + "mtype": 1 + }, + { + "id": "bid-same-3", + "impid": "imp-same-3", + "price": 1.30, + "adm": "<div>3</div>", + "crid": "crid-3", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-same-1", + "impid": "imp-same-1", + "price": 1.10, + "adm": "<div>1</div>", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-same-2", + "impid": "imp-same-2", + "price": 1.20, + "adm": "<div>2</div>", + "crid": "crid-2", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-same-3", + "impid": "imp-same-3", + "price": 1.30, + "adm": "<div>3</div>", + "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 new file mode 100644 index 0000000000..8e3f949460 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/no-currency-in-response.json @@ -0,0 +1,99 @@ +{ + "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": {} + } + ] + }, + "impIDs": [ + "imp-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.0, + "adm": "<div>Banner</div>", + "crid": "crid-1", + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.0, + "adm": "<div>Banner</div>", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json new file mode 100644 index 0000000000..8e3f14abfd --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/optional-params.json @@ -0,0 +1,228 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-empty-custom", + "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": "empty-custom", + "customParams": {} + } + } + }, + { + "id": "imp-numeric-bool", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "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, + "enabled": true, + "count": 3 + } + } + } + }, + { + "id": "imp-nested-custom", + "banner": { + "format": [ + { + "w": 970, + "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": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": [ + "970x250", + "728x90" + ] + } + } + } + }, + { + "id": "imp-no-custom", + "banner": { + "format": [ + { + "w": 468, + "h": 60 + } + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "no-custom" + } + } + } + ] + }, + "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": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-empty-custom", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "empty-custom", + "ext": {} + }, + { + "id": "imp-numeric-bool", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "tagid": "numeric-bool", + "ext": { + "customParams": { + "floor": 0.45, + "enabled": true, + "count": 3 + } + } + }, + { + "id": "imp-nested-custom", + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, + "tagid": "nested", + "ext": { + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": [ + "970x250", + "728x90" + ] + } + } + }, + { + "id": "imp-no-custom", + "banner": { + "format": [ + { + "w": 468, + "h": 60 + } + ] + }, + "tagid": "no-custom", + "ext": {} + } + ] + }, + "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 0000000000..952d026e80 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-audio.json @@ -0,0 +1,158 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-audio-large", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 15, + "maxduration": 60 + }, + "ext": { + "bidder": { + "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": {} + } + } + } + ] + }, + "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-audio-small", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 5, + "maxduration": 30 + }, + "tagid": "site-audio-small", + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-audio-large", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp4" + ], + "minduration": 15, + "maxduration": 60 + }, + "tagid": "site-audio-large", + "ext": {} + } + ] + }, + "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": "<audio src='small.mp3'></audio>", + "crid": "crid-site-audio-small-1", + "mtype": 3 + }, + { + "id": "bid-site-audio-large-1", + "impid": "imp-audio-large", + "price": 1.25, + "adm": "<audio src='large.mp3'></audio>", + "crid": "crid-site-audio-large-1", + "mtype": 3 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-site-audio-small-1", + "impid": "imp-audio-small", + "price": 0.75, + "adm": "<audio src='small.mp3'></audio>", + "crid": "crid-site-audio-small-1", + "mtype": 3 + }, + "type": "audio" + }, + { + "bid": { + "id": "bid-site-audio-large-1", + "impid": "imp-audio-large", + "price": 1.25, + "adm": "<audio src='large.mp3'></audio>", + "crid": "crid-site-audio-large-1", + "mtype": 3 + }, + "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 0000000000..2c0e908c6e --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-banner.json @@ -0,0 +1,229 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-empty-custom", + "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": "empty-custom", + "customParams": {} + } + } + }, + { + "id": "imp-nested-custom", + "banner": { + "format": [ + { + "w": 970, + "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": "nested", + "customParams": { + "placement": { + "position": "top", + "sticky": true + }, + "sizes": [ + "970x250", + "728x90" + ] + } + } + } + } + ] + }, + "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": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "imp-empty-custom", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "empty-custom", + "ext": {} + }, + { + "id": "imp-nested-custom", + "banner": { + "format": [ + { + "w": 970, + "h": 250 + } + ] + }, + "tagid": "nested", + "ext": { + "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": "<div>Banner 728x90</div>", + "crid": "crid-basic-1", + "mtype": 1 + }, + { + "id": "bid-empty-1", + "impid": "imp-empty-custom", + "price": 0.75, + "adm": "<div>Banner 300x250</div>", + "crid": "crid-empty-1", + "mtype": 1 + }, + { + "id": "bid-nested-1", + "impid": "imp-nested-custom", + "price": 2.5, + "adm": "<div>Banner 970x250</div>", + "crid": "crid-nested-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-basic-1", + "impid": "imp-basic", + "price": 1.25, + "adm": "<div>Banner 728x90</div>", + "crid": "crid-basic-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-empty-1", + "impid": "imp-empty-custom", + "price": 0.75, + "adm": "<div>Banner 300x250</div>", + "crid": "crid-empty-1", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-nested-1", + "impid": "imp-nested-custom", + "price": 2.5, + "adm": "<div>Banner 970x250</div>", + "crid": "crid-nested-1", + "mtype": 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 0000000000..4339d77473 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-empty-mutation.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "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" + } + } + } + } + ] + }, + "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-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "customParams": { + "foo": "bar" + } + } + } + ] + }, + "impIDs": [ + "imp-basic" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} 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 0000000000..fd198b1bc2 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-fallback.json @@ -0,0 +1,100 @@ +{ + "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": {} + } + ] + }, + "impIDs": [ + "imp-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.0, + "adm": "<div>Banner</div>", + "crid": "crid-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.0, + "adm": "<div>Banner</div>", + "crid": "crid-1", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} 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 0000000000..89954b712a --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-domain-mutation.json @@ -0,0 +1,71 @@ +{ + "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": { + "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" + } + } + } + } + ] + }, + "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": "https://not-empty.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "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 0000000000..9d4b018203 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-native.json @@ -0,0 +1,148 @@ +{ + "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": { + "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" + } + } + } + }, + { + "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": { + "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": {} + } + } + } + ] + }, + "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" + }, + "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": { + "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": {} + } + ] + }, + "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", + "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", + "mtype": 4 + } + ] + } + ], + "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", + "mtype": 4 + }, + "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", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} 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 0000000000..c027397c7f --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-eu.json @@ -0,0 +1,107 @@ +{ + "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": { + "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.1, + "adm": "<div>EU Banner 300x250</div>", + "crid": "crid-eu-1", + "mtype": 1 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-eu-1", + "impid": "imp-eu-banner", + "price": 1.1, + "adm": "<div>EU Banner 300x250</div>", + "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 0000000000..7c685fe00a --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-region-sg.json @@ -0,0 +1,113 @@ +{ + "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": { + "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.5, + "adm": "<VAST version='3.0'>SG Video Ad</VAST>", + "crid": "crid-sg-1", + "mtype": 2 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-sg-1", + "impid": "imp-sg-video", + "price": 4.5, + "adm": "<VAST version='3.0'>SG Video Ad</VAST>", + "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 new file mode 100644 index 0000000000..6d3f1aeefe --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/exemplary/site-video.json @@ -0,0 +1,184 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-video-large", + "video": { + "w": 1280, + "h": 720, + "mimes": [ + "video/mp4", + "video/webm" + ], + "minduration": 10, + "maxduration": 60, + "protocols": [ + 2, + 5, + 6 + ] + }, + "ext": { + "bidder": { + "route": "https://testsite.us-adx-admixer.rtb-stack.com/prebid?client=c4527281-5aa5-4c8e-bc53-a80bb3f99470&endpoint=309&ssp=145", + "tagId": "video-large", + "customParams": {} + } + } + } + ] + }, + "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-video-small", + "video": { + "w": 640, + "h": 360, + "mimes": [ + "video/mp4", + "video/webm" + ], + "minduration": 5, + "maxduration": 30, + "protocols": [ + 2, + 5 + ] + }, + "tagid": "video-small", + "ext": { + "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": {} + } + ] + }, + "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.0, + "adm": "<VAST version='3.0'>Small Video Ad</VAST>", + "crid": "crid-video-small-1", + "mtype": 2 + }, + { + "id": "bid-video-large-1", + "impid": "imp-video-large", + "price": 5.5, + "adm": "<VAST version='3.0'>Large Video Ad</VAST>", + "crid": "crid-video-large-1", + "mtype": 2 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-video-small-1", + "impid": "imp-video-small", + "price": 3.0, + "adm": "<VAST version='3.0'>Small Video Ad</VAST>", + "crid": "crid-video-small-1", + "mtype": 2 + }, + "type": "video" + }, + { + "bid": { + "id": "bid-video-large-1", + "impid": "imp-video-large", + "price": 5.5, + "adm": "<VAST version='3.0'>Large Video Ad</VAST>", + "crid": "crid-video-large-1", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} 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 0000000000..5d3c2f4509 --- /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-imp.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-imp.json new file mode 100644 index 0000000000..7fb55166c3 --- /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-mtype.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json new file mode 100644 index 0000000000..2b79830d11 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-mtype.json @@ -0,0 +1,94 @@ +{ + "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": {} + } + ] + }, + "impIDs": [ + "imp-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "rtbstack", + "bid": [ + { + "id": "bid-1", + "impid": "imp-banner", + "price": 1.0, + "adm": "<div>Banner</div>", + "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/bad-response.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json new file mode 100644 index 0000000000..2901ee1359 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/bad-response.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "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-banner", + "customParams": { + "foo": "bar" + } + } + } + } + ] + }, + "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", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "test-banner", + "ext": { + "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/bad-route-invalid-region.json b/adapters/rtbstack/rtbstacktest/supplemental/bad-route-invalid-region.json new file mode 100644 index 0000000000..156148b2cd --- /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 0000000000..ad6a6a463d --- /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/multi-route-partial-failure.json b/adapters/rtbstack/rtbstacktest/supplemental/multi-route-partial-failure.json new file mode 100644 index 0000000000..ebbf7c392d --- /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": "<div>good</div>", + "crid": "crid-good-1", + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-good-1", + "impid": "imp-good", + "price": 1.0, + "adm": "<div>good</div>", + "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/no-imps.json b/adapters/rtbstack/rtbstacktest/supplemental/no-imps.json new file mode 100644 index 0000000000..74130ada64 --- /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" + } + ] +} diff --git a/adapters/rtbstack/rtbstacktest/supplemental/status-204.json b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json new file mode 100644 index 0000000000..49d97f6c63 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-204.json @@ -0,0 +1,71 @@ +{ + "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": { + "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" + } + } + } + } + ] + }, + "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": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "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 0000000000..4b8f01fd8a --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/status-400.json @@ -0,0 +1,77 @@ +{ + "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": { + "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" + } + } + } + } + ] + }, + "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": "https://example.com" + }, + "imp": [ + { + "id": "imp-basic", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "basic", + "ext": { + "customParams": { + "foo": "bar" + } + } + } + ] + }, + "impIDs": [ + "imp-basic" + ] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "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 new file mode 100644 index 0000000000..04c1d35d98 --- /dev/null +++ b/adapters/rtbstack/rtbstacktest/supplemental/two-imps-one-is-bad.json @@ -0,0 +1,89 @@ +{ + "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": { + "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" + } + } + } + }, + { + "id": "imp-invalid", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": "invalid-json" + } + ] + }, + "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-partial", + "site": { + "page": "https://example.com", + "domain": "https://example.com" + }, + "imp": [ + { + "id": "imp-valid", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "valid-tag", + "ext": { + "customParams": { + "foo": "bar" + } + } + } + ] + }, + "impIDs": [ + "imp-valid" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ], + "expectedBidResponses": [] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 35619a799e..6a3d9b539e 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -199,6 +199,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/rise" "github.com/prebid/prebid-server/v4/adapters/roulax" "github.com/prebid/prebid-server/v4/adapters/rtbhouse" + "github.com/prebid/prebid-server/v4/adapters/rtbstack" "github.com/prebid/prebid-server/v4/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v4/adapters/sa_lunamedia" "github.com/prebid/prebid-server/v4/adapters/seedingAlliance" @@ -470,6 +471,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderRise: rise.Builder, openrtb_ext.BidderRoulax: roulax.Builder, openrtb_ext.BidderRTBHouse: rtbhouse.Builder, + openrtb_ext.BidderRTBStack: rtbstack.Builder, openrtb_ext.BidderRubicon: rubicon.Builder, openrtb_ext.BidderSeedingAlliance: seedingAlliance.Builder, openrtb_ext.BidderSeedtag: seedtag.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 9b7d162f74..97989ee54a 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -217,6 +217,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderRise, BidderRoulax, BidderRTBHouse, + BidderRTBStack, BidderRubicon, BidderSeedingAlliance, BidderSeedtag, @@ -592,6 +593,7 @@ const ( BidderRise BidderName = "rise" BidderRoulax BidderName = "roulax" BidderRTBHouse BidderName = "rtbhouse" + BidderRTBStack BidderName = "rtbstack" BidderRubicon BidderName = "rubicon" BidderSeedingAlliance BidderName = "seedingAlliance" BidderSeedtag BidderName = "seedtag" diff --git a/openrtb_ext/imp_rtbstack.go b/openrtb_ext/imp_rtbstack.go new file mode 100644 index 0000000000..d98e1b69bd --- /dev/null +++ b/openrtb_ext/imp_rtbstack.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpRTBStack struct { + 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 new file mode 100644 index 0000000000..34f02f0e97 --- /dev/null +++ b/static/bidder-info/rtbstack.yaml @@ -0,0 +1,19 @@ +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: + - banner + - video + - native + - audio + app: + mediaTypes: + - banner + - video + - native + - audio \ 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 0000000000..b5b90aefd0 --- /dev/null +++ b/static/bidder-params/rtbstack.json @@ -0,0 +1,24 @@ +{ + "$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": { + "route": { + "type": "string", + "minLength": 1, + "description": "Full route URL used to derive RTBStack endpoint (contains region, client, endpoint, ssp)." + }, + "tagId": { + "type": "string", + "description": "AdUnit tag id." + }, + "customParams": { + "type": "object", + "description": "Custom values for targeting." + } + }, + + "required": ["route", "tagId"] +} \ No newline at end of file From 23d75665e7dcd30e14fb38e2f85f6e41ddeab08e Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Thu, 14 May 2026 14:19:52 -0400 Subject: [PATCH 215/272] Adapter Code Coverage Workflow: Split into two stages (#4775) --- .../adapter-code-coverage-report.yml | 77 +++++++++++++++++++ .github/workflows/adapter-code-coverage.yml | 62 ++++----------- .../workflows/helpers/pull-request-utils.js | 2 +- 3 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/adapter-code-coverage-report.yml diff --git a/.github/workflows/adapter-code-coverage-report.yml b/.github/workflows/adapter-code-coverage-report.yml new file mode 100644 index 0000000000..c286ee6c6b --- /dev/null +++ b/.github/workflows/adapter-code-coverage-report.yml @@ -0,0 +1,77 @@ +name: Adapter Code Coverage Report + +on: + workflow_run: + workflows: ["Adapter Code Coverage"] + types: [completed] + +permissions: + pull-requests: write + contents: write + +jobs: + report-coverage: + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download Coverage Artifacts + uses: actions/download-artifact@v4 + with: + name: coverage-results + path: coverage-results + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Read PR Metadata + id: pr_metadata + run: | + echo "pr_number=$(cat coverage-results/pr-metadata/pr_number)" >> $GITHUB_OUTPUT + echo "head_sha=$(cat coverage-results/pr-metadata/head_sha)" >> $GITHUB_OUTPUT + echo "directories=$(cat coverage-results/pr-metadata/directories.json)" >> $GITHUB_OUTPUT + echo "coverage_dir=$(pwd)/coverage-results" >> $GITHUB_OUTPUT + + - name: Checkout Coverage Preview Branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: coverage-preview + repository: prebid/prebid-server + path: preview-repo + + - name: Upload Coverage Results + id: commit_coverage + run: | + timestamp=$(date +%s) + directory=preview-repo/.github/preview/${{ github.event.workflow_run.id }}_${timestamp} + mkdir -p $directory + cp -r coverage-results/*.html $directory/ + cd preview-repo + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add .github/preview/* + git commit -m 'Add coverage files for run ${{ github.event.workflow_run.id }}' + git push origin coverage-preview + echo "remote_coverage_preview_dir=.github/preview/${{ github.event.workflow_run.id }}_${timestamp}" >> $GITHUB_OUTPUT + + - name: Add Coverage Summary To Pull Request + if: steps.commit_coverage.outputs.remote_coverage_preview_dir != '' + uses: actions/github-script@v7 + with: + script: | + const utils = require('./.github/workflows/helpers/pull-request-utils.js') + const helper = utils.coverageHelper({ + github, context, + headSha: '${{ steps.pr_metadata.outputs.head_sha }}', + tmpCoverageDir: '${{ steps.pr_metadata.outputs.coverage_dir }}', + remoteCoverageDir: '${{ steps.commit_coverage.outputs.remote_coverage_preview_dir }}', + prNumber: ${{ steps.pr_metadata.outputs.pr_number }} + }) + const adapterDirectories = JSON.parse('${{ steps.pr_metadata.outputs.directories }}') + await helper.AddCoverageSummary(adapterDirectories) diff --git a/.github/workflows/adapter-code-coverage.yml b/.github/workflows/adapter-code-coverage.yml index 10dd9e8977..113c7d8776 100644 --- a/.github/workflows/adapter-code-coverage.yml +++ b/.github/workflows/adapter-code-coverage.yml @@ -1,12 +1,12 @@ name: Adapter Code Coverage on: - pull_request_target: + pull_request: paths: ["adapters/*/*.go"] permissions: - pull-requests: write - contents: write + contents: read + pull-requests: read jobs: run-coverage: @@ -21,8 +21,6 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - name: Discover Adapter Directories id: get_directories @@ -66,46 +64,20 @@ jobs: done echo "coverage_dir=${temp_dir}" >> $GITHUB_OUTPUT - # remove pull request branch files - cd .. - rm -f -r ./* - - - name: Checkout Coverage Preview Branch - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: coverage-preview - repository: prebid/prebid-server - - - name: Upload Coverage Results - if: steps.run_coverage.outputs.coverage_dir != '' - id: commit_coverage - run: | - directory=.github/preview/${{ github.run_id }}_$(date +%s) - mkdir -p $directory - cp -r ${{ steps.run_coverage.outputs.coverage_dir }}/*.html ./$directory - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git add $directory/* - git commit -m 'Add coverage files' - git push origin coverage-preview - echo "remote_coverage_preview_dir=${directory}" >> $GITHUB_OUTPUT - - - name: Checkout Master Branch + - name: Prepare Artifacts if: steps.get_directories.outputs.result != '' - run: git checkout master + run: | + mkdir -p ./coverage-artifacts/pr-metadata + cp ${{ steps.run_coverage.outputs.coverage_dir }}/*.html ./coverage-artifacts/ 2>/dev/null || true + cp ${{ steps.run_coverage.outputs.coverage_dir }}/*.txt ./coverage-artifacts/ 2>/dev/null || true + echo '${{ steps.get_directories.outputs.result }}' > ./coverage-artifacts/pr-metadata/directories.json + echo '${{ github.event.pull_request.number }}' > ./coverage-artifacts/pr-metadata/pr_number + echo '${{ github.event.pull_request.head.sha }}' > ./coverage-artifacts/pr-metadata/head_sha - - name: Add Coverage Summary To Pull Request - if: steps.run_coverage.outputs.coverage_dir != '' && steps.commit_coverage.outputs.remote_coverage_preview_dir != '' - uses: actions/github-script@v7 + - name: Upload Coverage Artifacts + if: steps.run_coverage.outputs.coverage_dir != '' + uses: actions/upload-artifact@v4 with: - script: | - const utils = require('./.github/workflows/helpers/pull-request-utils.js') - const helper = utils.coverageHelper({ - github, context, - headSha: '${{ github.event.pull_request.head.sha }}', - tmpCoverageDir: '${{ steps.run_coverage.outputs.coverage_dir }}', - remoteCoverageDir: '${{ steps.commit_coverage.outputs.remote_coverage_preview_dir }}' - }) - const adapterDirectories = JSON.parse('${{ steps.get_directories.outputs.result }}') - await helper.AddCoverageSummary(adapterDirectories) + name: coverage-results + path: ./coverage-artifacts + retention-days: 1 diff --git a/.github/workflows/helpers/pull-request-utils.js b/.github/workflows/helpers/pull-request-utils.js index 73c8039647..70e8570e4b 100644 --- a/.github/workflows/helpers/pull-request-utils.js +++ b/.github/workflows/helpers/pull-request-utils.js @@ -361,7 +361,7 @@ class coverageHelper { this.owner = input.context.repo.owner this.repo = input.context.repo.repo this.github = input.github - this.pullRequestNumber = input.context.payload.pull_request.number + this.pullRequestNumber = input.prNumber || input.context.payload.pull_request.number this.headSha = input.headSha this.previewBaseURL = `https://htmlpreview.github.io/?https://github.com/${this.owner}/${this.repo}/coverage-preview/${input.remoteCoverageDir}` this.tmpCoverDir = input.tmpCoverageDir From 2a3bc5e3a7c0f656369280854e1f775555de0c58 Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Thu, 14 May 2026 14:33:19 -0400 Subject: [PATCH 216/272] Pin trivy-action to v0.35.0 SHA for supply chain security (#4776) --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index d3831d8044..f0a4ac68d8 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -20,7 +20,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Run Trivy - uses: aquasecurity/trivy-action@master + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: scan-type: 'fs' ignore-unfixed: true From f4e2087677964cb4a89f721630c5a35bc673b091 Mon Sep 17 00:00:00 2001 From: anishb-ms <122366082+anishb-ms@users.noreply.github.com> Date: Sat, 16 May 2026 02:28:58 +0530 Subject: [PATCH 217/272] Adapter Code Coverage Workflow: Support Go version upgrades (#4760) --- .github/workflows/adapter-code-coverage.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/adapter-code-coverage.yml b/.github/workflows/adapter-code-coverage.yml index 113c7d8776..a085d85ffe 100644 --- a/.github/workflows/adapter-code-coverage.yml +++ b/.github/workflows/adapter-code-coverage.yml @@ -12,16 +12,16 @@ jobs: run-coverage: runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.0 - - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Discover Adapter Directories id: get_directories uses: actions/github-script@v7 From a90c8d862ede686b951a40b95a34e8ced863d141 Mon Sep 17 00:00:00 2001 From: anishb-ms <122366082+anishb-ms@users.noreply.github.com> Date: Wed, 20 May 2026 01:20:15 +0530 Subject: [PATCH 218/272] Coop Cookie Sync: Add option to skip appending remaining available bidders (#4764) --- config/account.go | 9 ++-- endpoints/cookie_sync.go | 6 ++- endpoints/cookie_sync_test.go | 56 ++++++++++++++++---- usersync/bidderchooser.go | 10 ++-- usersync/bidderchooser_test.go | 95 ++++++++++++++++++++-------------- usersync/chooser.go | 5 +- 6 files changed, 119 insertions(+), 62 deletions(-) diff --git a/config/account.go b/config/account.go index a773e6fbbd..cc403f962b 100644 --- a/config/account.go +++ b/config/account.go @@ -58,10 +58,11 @@ type Account struct { // CookieSync represents the account-level defaults for the cookie sync endpoint. type CookieSync struct { - DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` - MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` - DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` - PriorityGroups [][]string `mapstructure:"priority_groups" json:"priority_groups"` + DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` + MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` + DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` + PriorityGroups [][]string `mapstructure:"priority_groups" json:"priority_groups"` + PriorityGroupsOnly *bool `mapstructure:"priority_groups_only" json:"priority_groups_only"` } // AccountCCPA represents account-specific CCPA configuration diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index 0c1c1fb274..8b90cb2ff8 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -30,6 +30,7 @@ import ( "github.com/prebid/prebid-server/v4/stored_requests" "github.com/prebid/prebid-server/v4/usersync" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/ptrutil" stringutil "github.com/prebid/prebid-server/v4/util/stringutil" "github.com/prebid/prebid-server/v4/util/timeutil" ) @@ -183,8 +184,9 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, ma rx := usersync.Request{ Bidders: request.Bidders, Cooperative: usersync.Cooperative{ - Enabled: (request.CooperativeSync != nil && *request.CooperativeSync) || (request.CooperativeSync == nil && c.config.UserSync.Cooperative.EnabledByDefault), - PriorityGroups: c.findPriorityGroups(account.CookieSync), + Enabled: (request.CooperativeSync != nil && *request.CooperativeSync) || (request.CooperativeSync == nil && c.config.UserSync.Cooperative.EnabledByDefault), + PriorityGroups: c.findPriorityGroups(account.CookieSync), + PriorityGroupsOnly: ptrutil.ValueOrDefault(account.CookieSync.PriorityGroupsOnly), }, Debug: request.Debug, Limit: limit, diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index 3da85fb71a..503eb9c35b 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -2603,7 +2603,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { } // createAccountJSON creates a JSON representation of account config for testing -func createAccountJSON(priorityGroups [][]string, defaultCoopSync *bool) json.RawMessage { +func createAccountJSON(priorityGroups [][]string, defaultCoopSync *bool, priorityGroupsOnly *bool) json.RawMessage { account := map[string]interface{}{ "cookie_sync": map[string]interface{}{ "priority_groups": priorityGroups, @@ -2614,6 +2614,10 @@ func createAccountJSON(priorityGroups [][]string, defaultCoopSync *bool) json.Ra account["cookie_sync"].(map[string]interface{})["default_coop_sync"] = *defaultCoopSync } + if priorityGroupsOnly != nil { + account["cookie_sync"].(map[string]interface{})["priority_groups_only"] = *priorityGroupsOnly + } + jsonData, _ := json.Marshal(account) return json.RawMessage(jsonData) } @@ -2652,13 +2656,15 @@ func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { } testCases := []struct { - description string - givenRequestBody string - givenAccountPriorityGroups [][]string - givenAccountDefaultCoopSync *bool - givenGlobalPriorityGroups [][]string - givenCooperativeEnabledByDef bool - shouldContainBidders []string + description string + givenRequestBody string + givenAccountPriorityGroups [][]string + givenAccountDefaultCoopSync *bool + givenAccountPriorityGroupsOnly *bool + givenGlobalPriorityGroups [][]string + givenCooperativeEnabledByDef bool + shouldContainBidders []string + shouldNotContainBidders []string }{ { description: "Account-level priority groups used with cooperative sync enabled", @@ -2713,6 +2719,31 @@ func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { givenCooperativeEnabledByDef: false, shouldContainBidders: []string{"appnexus", "rubicon", "pubmatic"}, }, + { + description: "Priority groups only — remaining bidders excluded", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"rubicon"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenAccountPriorityGroupsOnly: ptrutil.ToPtr(true), + givenGlobalPriorityGroups: [][]string{{"ignored"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus", "rubicon"}, + shouldNotContainBidders: []string{"pubmatic"}, + }, + { + description: "Priority groups only false — remaining bidders included", + givenRequestBody: `{"bidders":["appnexus"], "coopSync": true, "limit": 10, "account": "test_account"}`, + givenAccountPriorityGroups: [][]string{ + {"rubicon"}, + }, + givenAccountDefaultCoopSync: ptrutil.ToPtr(true), + givenAccountPriorityGroupsOnly: ptrutil.ToPtr(false), + givenGlobalPriorityGroups: [][]string{{"ignored"}}, + givenCooperativeEnabledByDef: false, + shouldContainBidders: []string{"appnexus", "rubicon", "pubmatic"}, + }, } for _, tc := range testCases { @@ -2750,7 +2781,7 @@ func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { &mockAnalytics, &FakeAccountsFetcher{ AccountData: map[string]json.RawMessage{ - "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync), + "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync, tc.givenAccountPriorityGroupsOnly), }, }, bidders, @@ -2780,6 +2811,11 @@ func TestCookieSyncPriorityGroupsIntegration(t *testing.T) { for _, expected := range tc.shouldContainBidders { assert.Contains(t, actualBidders, expected, "Expected bidder %s to be present in response", expected) } + + // Check that excluded bidders are not present + for _, excluded := range tc.shouldNotContainBidders { + assert.NotContains(t, actualBidders, excluded, "Bidder %s should not be present in response", excluded) + } }) } } @@ -2923,7 +2959,7 @@ func TestCookieSyncPriorityGroupsEdgeCases(t *testing.T) { &mockAnalytics, &FakeAccountsFetcher{ AccountData: map[string]json.RawMessage{ - "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync), + "test_account": createAccountJSON(tc.givenAccountPriorityGroups, tc.givenAccountDefaultCoopSync, nil), }, }, bidders, diff --git a/usersync/bidderchooser.go b/usersync/bidderchooser.go index 1b01e5116e..046d5c3a19 100644 --- a/usersync/bidderchooser.go +++ b/usersync/bidderchooser.go @@ -13,7 +13,7 @@ type standardBidderChooser struct { func (c standardBidderChooser) choose(requested, available []string, cooperative Cooperative) []string { if cooperative.Enabled { - return c.chooseCooperative(requested, available, cooperative.PriorityGroups) + return c.chooseCooperative(requested, available, cooperative) } if len(requested) == 0 { @@ -23,7 +23,7 @@ func (c standardBidderChooser) choose(requested, available []string, cooperative return c.shuffledCopy(requested) } -func (c standardBidderChooser) chooseCooperative(requested, available []string, priorityGroups [][]string) []string { +func (c standardBidderChooser) chooseCooperative(requested, available []string, cooperative Cooperative) []string { // allocate enough memory for the slice to try to avoid re-allocation. the 50% overhead is a guess // at a satisfactory value. since all available bidders are included in the slice, along with // requested and prioritized bidders, expect there to be be many duplicates. the duplicate are @@ -35,12 +35,14 @@ func (c standardBidderChooser) chooseCooperative(requested, available []string, bidders = c.shuffledAppend(bidders, requested) // priority groups - for _, group := range priorityGroups { + for _, group := range cooperative.PriorityGroups { bidders = c.shuffledAppend(bidders, group) } // available - bidders = c.shuffledAppend(bidders, available) + if !cooperative.PriorityGroupsOnly { + bidders = c.shuffledAppend(bidders, available) + } return bidders } diff --git a/usersync/bidderchooser_test.go b/usersync/bidderchooser_test.go index fe7d296f1f..cdf007aa3c 100644 --- a/usersync/bidderchooser_test.go +++ b/usersync/bidderchooser_test.go @@ -62,6 +62,12 @@ func TestBidderChooserChoose(t *testing.T) { givenCooperative: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}}, expected: []string{"r2", "r1", "pr1B", "pr1A", "pr2B", "pr2A", "a2", "a1"}, }, + { + description: "Coop - PriorityGroupsOnly", + givenRequested: []string{"r1", "r2"}, + givenCooperative: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}}, PriorityGroupsOnly: true}, + expected: []string{"r2", "r1", "pr1B", "pr1A"}, + }, } for _, test := range testCases { @@ -76,55 +82,64 @@ func TestBidderChooserCooperative(t *testing.T) { shuffler := reverseShuffler{} available := []string{"a1", "a2"} - testCases := []struct { - description string - givenRequested []string - givenPriorityGroups [][]string - expected []string + testCases := map[string]struct { + givenRequested []string + givenCoop Cooperative + expected []string }{ - { - description: "Nil", - givenRequested: nil, - givenPriorityGroups: nil, - expected: []string{"a2", "a1"}, + "nil": { + givenRequested: nil, + givenCoop: Cooperative{Enabled: true}, + expected: []string{"a2", "a1"}, }, - { - description: "Empty", - givenRequested: []string{}, - givenPriorityGroups: [][]string{}, - expected: []string{"a2", "a1"}, + "empty": { + givenRequested: []string{}, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{}}, + expected: []string{"a2", "a1"}, }, - { - description: "Requested", - givenRequested: []string{"r1", "r2"}, - givenPriorityGroups: nil, - expected: []string{"r2", "r1", "a2", "a1"}, + "requested": { + givenRequested: []string{"r1", "r2"}, + givenCoop: Cooperative{Enabled: true}, + expected: []string{"r2", "r1", "a2", "a1"}, }, - { - description: "Priority Groups - One", - givenRequested: nil, - givenPriorityGroups: [][]string{{"pr1A", "pr1B"}}, - expected: []string{"pr1B", "pr1A", "a2", "a1"}, + "priority_groups_one": { + givenRequested: nil, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}}}, + expected: []string{"pr1B", "pr1A", "a2", "a1"}, }, - { - description: "Priority Groups - Many", - givenRequested: nil, - givenPriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}, - expected: []string{"pr1B", "pr1A", "pr2B", "pr2A", "a2", "a1"}, + "priority_groups_many": { + givenRequested: nil, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}}, + expected: []string{"pr1B", "pr1A", "pr2B", "pr2A", "a2", "a1"}, }, - { - description: "Requested + Priority Groups", - givenRequested: []string{"r1", "r2"}, - givenPriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}, - expected: []string{"r2", "r1", "pr1B", "pr1A", "pr2B", "pr2A", "a2", "a1"}, + "requested_and_priority_groups": { + givenRequested: []string{"r1", "r2"}, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}}, + expected: []string{"r2", "r1", "pr1B", "pr1A", "pr2B", "pr2A", "a2", "a1"}, + }, + "priority_groups_only_no_remaining": { + givenRequested: []string{"r1", "r2"}, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}}, PriorityGroupsOnly: true}, + expected: []string{"r2", "r1", "pr1B", "pr1A"}, + }, + "priority_groups_only_no_requested": { + givenRequested: nil, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{{"pr1A", "pr1B"}, {"pr2A", "pr2B"}}, PriorityGroupsOnly: true}, + expected: []string{"pr1B", "pr1A", "pr2B", "pr2A"}, + }, + "priority_groups_only_empty_groups": { + givenRequested: []string{"r1", "r2"}, + givenCoop: Cooperative{Enabled: true, PriorityGroups: [][]string{}, PriorityGroupsOnly: true}, + expected: []string{"r2", "r1"}, }, } - for _, test := range testCases { - chooser := standardBidderChooser{shuffler: shuffler} - result := chooser.chooseCooperative(test.givenRequested, available, test.givenPriorityGroups) - - assert.Equal(t, test.expected, result, test.description) + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + chooser := standardBidderChooser{shuffler: shuffler} + result := chooser.chooseCooperative(test.givenRequested, available, test.givenCoop) + assert.Equal(t, test.expected, result) + }) } } diff --git a/usersync/chooser.go b/usersync/chooser.go index bc2d0812a7..88913a76cc 100644 --- a/usersync/chooser.go +++ b/usersync/chooser.go @@ -46,8 +46,9 @@ type Request struct { // Cooperative specifies the settings for cooperative syncing for a given request, where bidders // other than those used by the publisher are considered for syncing. type Cooperative struct { - Enabled bool - PriorityGroups [][]string + Enabled bool + PriorityGroups [][]string + PriorityGroupsOnly bool } // Result specifies which bidders were included in the evaluation and which syncers were chosen. From 1d44c3fd9cc8c7504214bf0b2315d99d93427138 Mon Sep 17 00:00:00 2001 From: Pat Diggins <89027546+PBDMSFT@users.noreply.github.com> Date: Tue, 19 May 2026 16:59:08 -0400 Subject: [PATCH 219/272] audienceNetwork: Add rewarded video support and allow rewarded interstitials (#4763) Co-authored-by: Pat Diggins <pdiggins+microsoft@microsoft.com> Co-authored-by: bsardo <1168933+bsardo@users.noreply.github.com> --- .../rewarded-video-interstitial.json | 146 ++++++++++++++++++ .../exemplary/rewarded-video-prebid-ext.json | 144 +++++++++++++++++ .../exemplary/rewarded-video-rwdd.json | 142 +++++++++++++++++ .../exemplary/video-non-rewarded.json | 140 +++++++++++++++++ .../invalid-interstitial-native.json | 35 +++++ ...alid-interstitial-video-non-rewarded.json} | 2 +- adapters/audienceNetwork/facebook.go | 43 +++++- 7 files changed, 649 insertions(+), 3 deletions(-) create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-prebid-ext.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-rwdd.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/video-non-rewarded.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json rename adapters/audienceNetwork/audienceNetworktest/supplemental/{invalid-interstitial.json => invalid-interstitial-video-non-rewarded.json} (96%) diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json new file mode 100644 index 0000000000..132df2f75f --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json @@ -0,0 +1,146 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + }, + "prebid": { + "is_rewarded_inventory": 1 + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0, + "ext": { + "videotype": "rewarded" + } + }, + "instl": 1, + "rwdd": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-prebid-ext.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-prebid-ext.json new file mode 100644 index 0000000000..b708c8d40d --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-prebid-ext.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + }, + "prebid": { + "is_rewarded_inventory": 1 + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0, + "ext": { + "videotype": "rewarded" + } + }, + "rwdd": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-rwdd.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-rwdd.json new file mode 100644 index 0000000000..1fcbc2f0a9 --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-rwdd.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "rwdd": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0, + "ext": { + "videotype": "rewarded" + } + }, + "rwdd": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":400,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/video-non-rewarded.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/video-non-rewarded.json new file mode 100644 index 0000000000..eaf4f614ab --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/video-non-rewarded.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + }, + "prebid": { + "is_rewarded_inventory": 0 + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0 + }, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json new file mode 100644 index 0000000000..e2e88a5785 --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json @@ -0,0 +1,35 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [{ + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}}]}", + "ver": "1.1" + }, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "expectedMakeRequestsErrors": [{ + "value": "imp #test-imp-id: interstitial imps are only supported for banner and rewarded video", + "comparison": "literal" + }] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json similarity index 96% rename from adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial.json rename to adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json index 68ca804481..b98ff8cbf8 100644 --- a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial.json +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json @@ -34,7 +34,7 @@ "tmax": 500 }, "expectedMakeRequestsErrors": [{ - "value": "imp #test-imp-id: interstitial imps are only supported for banner", + "value": "imp #test-imp-id: interstitial imps are only supported for banner and rewarded video", "comparison": "literal" }] } \ No newline at end of file diff --git a/adapters/audienceNetwork/facebook.go b/adapters/audienceNetwork/facebook.go index acf618ecb2..4583881b01 100644 --- a/adapters/audienceNetwork/facebook.go +++ b/adapters/audienceNetwork/facebook.go @@ -150,6 +150,33 @@ func (a *adapter) modifyRequest(out *openrtb2.BidRequest) error { return err } + // Preserve rewarded signal before clearing ext. For ORTB 2.5 adapters, + // PBS moves imp.rwdd to imp.ext.prebid.is_rewarded_inventory via ConvertDownTo25. + // Since we clear imp.Ext below, the signal would be lost. Extract it now and + // restore it on the struct field so it serializes as imp.rwdd for Meta. + if imp.Rwdd != 1 && imp.Ext != nil { + if val, err := jsonparser.GetInt(imp.Ext, "prebid", "is_rewarded_inventory"); err == nil && val == 1 { + imp.Rwdd = 1 + } + } + if imp.Rwdd == 1 && imp.Video != nil { + videoCopy := *imp.Video + var extMap map[string]interface{} + if videoCopy.Ext != nil { + if err := jsonutil.Unmarshal(videoCopy.Ext, &extMap); err != nil { + return err + } + } else { + extMap = make(map[string]interface{}) + } + extMap["videotype"] = "rewarded" + videoCopy.Ext, err = jsonutil.Marshal(extMap) + if err != nil { + return err + } + imp.Video = &videoCopy + } + imp.TagID = pubId + "_" + plmtId imp.Ext = nil @@ -169,9 +196,9 @@ func (a *adapter) modifyRequest(out *openrtb2.BidRequest) error { func modifyImp(out *openrtb2.Imp) error { impType := resolveImpType(out) - if out.Instl == 1 && impType != openrtb_ext.BidTypeBanner { + if out.Instl == 1 && !isValidInterstitial(impType, out.Rwdd) { return &errortypes.BadInput{ - Message: fmt.Sprintf("imp #%s: interstitial imps are only supported for banner", out.ID), + Message: fmt.Sprintf("imp #%s: interstitial imps are only supported for banner and rewarded video", out.ID), } } @@ -214,6 +241,18 @@ func modifyImp(out *openrtb2.Imp) error { return nil } +func isValidInterstitial(impType openrtb_ext.BidType, rwdd int8) bool { + if impType == openrtb_ext.BidTypeBanner { + return true + } + + if impType == openrtb_ext.BidTypeVideo && rwdd == 1 { + return true + } + + return false +} + func extractPlacementAndPublisher(out *openrtb2.Imp) (string, string, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(out.Ext, &bidderExt); err != nil { From 471d2f552f3237f26eba7aabc9a3834a78dc4185 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Tue, 26 May 2026 19:42:34 +0530 Subject: [PATCH 220/272] Modules: Concurrency module context fix (#4603) Co-authored-by: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com> --- exchange/exchange_test.go | 2 +- hooks/hookexecution/context.go | 25 +- hooks/hookexecution/executor.go | 2 +- hooks/hookexecution/executor_test.go | 314 +++++++++++------- hooks/hookexecution/mocks_test.go | 24 +- hooks/hookstage/invocation.go | 74 ++++- .../devicedetection/evidence_extractor.go | 8 +- .../evidence_extractor_test.go | 108 +++--- .../hook_auction_entrypoint.go | 8 +- .../fiftyonedegrees/devicedetection/module.go | 2 +- .../devicedetection/module_test.go | 21 +- .../ortb2blocking/hook_bidderrequest.go | 5 +- .../ortb2blocking/hook_raw_bidder_response.go | 4 +- modules/prebid/ortb2blocking/module_test.go | 134 ++++++-- .../wurfl_devicedetection/module.go | 10 +- .../wurfl_devicedetection/module_test.go | 43 ++- modules/scope3/rtd/module.go | 43 ++- modules/scope3/rtd/module_test.go | 26 +- 18 files changed, 586 insertions(+), 267 deletions(-) diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index c18ebd5af9..7770a2ec34 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -5996,7 +5996,7 @@ func (e mockUpdateBidRequestHook) HandleBidderRequestHook(_ context.Context, mct }, hookstage.MutationUpdate, "bidRequest", "site.domain", ) - mctx.ModuleContext = map[string]interface{}{"some-ctx": "some-ctx"} + mctx.ModuleContext.Set("some-ctx", "some-ctx") return hookstage.HookResult[hookstage.BidderRequestPayload]{ChangeSet: c, ModuleContext: mctx.ModuleContext}, nil } diff --git a/hooks/hookexecution/context.go b/hooks/hookexecution/context.go index fee4e7385a..d0d8073dda 100644 --- a/hooks/hookexecution/context.go +++ b/hooks/hookexecution/context.go @@ -43,24 +43,27 @@ func (ctx executionContext) getModuleContext(moduleName string) hookstage.Module // moduleContexts preserves data the module wants to pass to itself from earlier stages to later stages. type moduleContexts struct { sync.RWMutex - ctxs map[string]hookstage.ModuleContext // format: {"module_name": hookstage.ModuleContext} + ctxs map[string]*hookstage.ModuleContext // format: {"module_name": hookstage.ModuleContext} } -func (mc *moduleContexts) put(moduleName string, mCtx hookstage.ModuleContext) { +func (mc *moduleContexts) put(moduleName string, mCtx *hookstage.ModuleContext) { + if mc == nil { + return + } mc.Lock() defer mc.Unlock() - newCtx := mCtx - if existingCtx, ok := mc.ctxs[moduleName]; ok && existingCtx != nil { - for k, v := range mCtx { - existingCtx[k] = v - } - newCtx = existingCtx + existingCtx, ok := mc.ctxs[moduleName] + if !ok { + mc.ctxs[moduleName] = mCtx + return } - mc.ctxs[moduleName] = newCtx + + // Add new data to existing context + existingCtx.SetAll(mCtx.GetAll()) } -func (mc *moduleContexts) get(moduleName string) (hookstage.ModuleContext, bool) { +func (mc *moduleContexts) get(moduleName string) (*hookstage.ModuleContext, bool) { mc.RLock() defer mc.RUnlock() mCtx, ok := mc.ctxs[moduleName] @@ -72,4 +75,4 @@ type stageModuleContext struct { groupCtx []groupModuleContext } -type groupModuleContext map[string]hookstage.ModuleContext +type groupModuleContext map[string]*hookstage.ModuleContext diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go index c33cfcdda5..eb66caf64a 100644 --- a/hooks/hookexecution/executor.go +++ b/hooks/hookexecution/executor.go @@ -68,7 +68,7 @@ func NewHookExecutor(builder hooks.ExecutionPlanBuilder, endpoint string, me met endpoint: endpoint, planBuilder: builder, stageOutcomes: []StageOutcome{}, - moduleContexts: &moduleContexts{ctxs: make(map[string]hookstage.ModuleContext)}, + moduleContexts: &moduleContexts{ctxs: make(map[string]*hookstage.ModuleContext)}, metricEngine: me, } } diff --git a/hooks/hookexecution/executor_test.go b/hooks/hookexecution/executor_test.go index dd309dffa9..3dd0e76c02 100644 --- a/hooks/hookexecution/executor_test.go +++ b/hooks/hookexecution/executor_test.go @@ -61,7 +61,7 @@ func TestExecuteEntrypointStage(t *testing.T) { const body string = `{"name": "John", "last_name": "Doe"}` const urlString string = "https://prebid.com/openrtb2/auction" - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} testCases := []struct { description string @@ -84,7 +84,7 @@ func TestExecuteEntrypointStage(t *testing.T) { expectedHeader: http.Header{}, expectedQuery: url.Values{}, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -299,9 +299,18 @@ func TestExecuteEntrypointStage(t *testing.T) { expectedHeader: http.Header{}, expectedQuery: url.Values{}, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"entrypoint-ctx-1": "some-ctx-1", "entrypoint-ctx-3": "some-ctx-3"}, - "module-2": {"entrypoint-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -418,7 +427,7 @@ func TestExecuteRawAuctionStage(t *testing.T) { const bodyUpdated string = `{"last_name": "Doe", "foo": "bar"}` const urlString string = "https://prebid.com/openrtb2/auction" - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} testCases := []struct { description string @@ -437,7 +446,7 @@ func TestExecuteRawAuctionStage(t *testing.T) { givenPlanBuilder: hooks.EmptyPlanBuilder{}, expectedBody: body, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -613,9 +622,18 @@ func TestExecuteRawAuctionStage(t *testing.T) { givenPlanBuilder: TestWithModuleContextsPlanBuilder{}, expectedBody: body, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"raw-auction-ctx-1": "some-ctx-1", "raw-auction-ctx-3": "some-ctx-3"}, - "module-2": {"raw-auction-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("raw-auction-ctx-1", "some-ctx-1") + mc.Set("raw-auction-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("raw-auction-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -691,7 +709,7 @@ func TestExecuteRawAuctionStage(t *testing.T) { } func TestExecuteProcessedAuctionStage(t *testing.T) { - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} req := openrtb2.BidRequest{ID: "some-id", User: &openrtb2.User{ID: "user-id"}} reqUpdated := openrtb2.BidRequest{ID: "some-id", User: &openrtb2.User{ID: "user-id", Yob: 2000, Consent: "true"}} @@ -710,7 +728,7 @@ func TestExecuteProcessedAuctionStage(t *testing.T) { givenRequest: openrtb_ext.RequestWrapper{BidRequest: &req}, expectedRequest: req, expectedErr: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -831,9 +849,18 @@ func TestExecuteProcessedAuctionStage(t *testing.T) { givenRequest: openrtb_ext.RequestWrapper{BidRequest: &req}, expectedRequest: req, expectedErr: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"processed-auction-ctx-1": "some-ctx-1", "processed-auction-ctx-3": "some-ctx-3"}, - "module-2": {"processed-auction-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("processed-auction-ctx-1", "some-ctx-1") + mc.Set("processed-auction-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("processed-auction-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -910,7 +937,7 @@ func TestExecuteProcessedAuctionStage(t *testing.T) { func TestExecuteBidderRequestStage(t *testing.T) { bidderName := "the-bidder" - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} expectedBidderRequest := &openrtb2.BidRequest{ID: "some-id", User: &openrtb2.User{ID: "user-id"}} expectedUpdatedBidderRequest := &openrtb2.BidRequest{ @@ -938,7 +965,7 @@ func TestExecuteBidderRequestStage(t *testing.T) { givenPlanBuilder: hooks.EmptyPlanBuilder{}, expectedBidderRequest: expectedBidderRequest, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -1106,9 +1133,17 @@ func TestExecuteBidderRequestStage(t *testing.T) { givenPlanBuilder: TestWithModuleContextsPlanBuilder{}, expectedBidderRequest: expectedBidderRequest, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"bidder-request-ctx-1": "some-ctx-1"}, - "module-2": {"bidder-request-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("bidder-request-ctx-1", "some-ctx-1") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("bidder-request-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -1218,7 +1253,7 @@ func buildDefaultActivityConfig(componentName string, allow bool) config.Activit } func TestExecuteRawBidderResponseStage(t *testing.T) { - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} resp := adapters.BidderResponse{Bids: []*adapters.TypedBid{{DealPriority: 1}}} expResp := adapters.BidderResponse{Bids: []*adapters.TypedBid{{DealPriority: 10}}} vEntity := entity("the-bidder") @@ -1238,7 +1273,7 @@ func TestExecuteRawBidderResponseStage(t *testing.T) { givenBidderResponse: resp, expectedBidderResponse: resp, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -1357,9 +1392,18 @@ func TestExecuteRawBidderResponseStage(t *testing.T) { givenBidderResponse: resp, expectedBidderResponse: expResp, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"raw-bidder-response-ctx-1": "some-ctx-1", "raw-bidder-response-ctx-3": "some-ctx-3"}, - "module-2": {"raw-bidder-response-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("raw-bidder-response-ctx-1", "some-ctx-1") + mc.Set("raw-bidder-response-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("raw-bidder-response-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -1435,7 +1479,7 @@ func TestExecuteRawBidderResponseStage(t *testing.T) { } func TestExecuteAllProcessedBidResponsesStage(t *testing.T) { - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} expectedAllProcBidResponses := map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{ "some-bidder": {Bids: []*entities.PbsOrtbBid{{DealPriority: 1}}}, @@ -1461,7 +1505,7 @@ func TestExecuteAllProcessedBidResponsesStage(t *testing.T) { givenPlanBuilder: hooks.EmptyPlanBuilder{}, expectedBiddersResponse: expectedAllProcBidResponses, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -1642,9 +1686,17 @@ func TestExecuteAllProcessedBidResponsesStage(t *testing.T) { givenPlanBuilder: TestWithModuleContextsPlanBuilder{}, expectedBiddersResponse: expectedAllProcBidResponses, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"all-processed-bid-responses-ctx-1": "some-ctx-1"}, - "module-2": {"all-processed-bid-responses-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("all-processed-bid-responses-ctx-1", "some-ctx-1") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("all-processed-bid-responses-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -1709,7 +1761,7 @@ func TestExecuteAllProcessedBidResponsesStage(t *testing.T) { } func TestExecuteAuctionResponseStage(t *testing.T) { - foobarModuleCtx := &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}} + foobarModuleCtx := &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}} resp := &openrtb2.BidResponse{CustomData: "some-custom-data"} expResp := &openrtb2.BidResponse{CustomData: "new-custom-data"} @@ -1728,7 +1780,7 @@ func TestExecuteAuctionResponseStage(t *testing.T) { givenResponse: resp, expectedResponse: resp, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -1877,9 +1929,18 @@ func TestExecuteAuctionResponseStage(t *testing.T) { givenResponse: resp, expectedResponse: resp, expectedReject: nil, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"auction-response-ctx-1": "some-ctx-1", "auction-response-ctx-3": "some-ctx-3"}, - "module-2": {"auction-response-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("auction-response-ctx-1", "some-ctx-1") + mc.Set("auction-response-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("auction-response-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -2000,7 +2061,7 @@ func TestExecuteExitpointStage(t *testing.T) { expectedResponseHeaders: http.Header{ "Content-Type": []string{"application/json"}, }, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{}}, expectedStageOutcomes: []StageOutcome{}, }, { @@ -2027,7 +2088,7 @@ func TestExecuteExitpointStage(t *testing.T) { expectedResponseHeaders: http.Header{ "Content-Type": []string{"application/xml"}, }, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}}, expectedStageOutcomes: []StageOutcome{ { Entity: "exitpoint", @@ -2068,7 +2129,7 @@ func TestExecuteExitpointStage(t *testing.T) { }, expectedResponse: `<VAST version="2.0"/>`, expectedResponseHeaders: http.Header{"Content-Type": []string{"application/xml"}}, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}}, expectedStageOutcomes: []StageOutcome{ { Entity: entityExitpoint, @@ -2144,7 +2205,7 @@ func TestExecuteExitpointStage(t *testing.T) { }, expectedResponse: `<VAST version="2.0"/>`, expectedResponseHeaders: http.Header{"Content-Type": []string{"application/xml"}}, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{"foobar": nil}}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{"foobar": nil}}, expectedStageOutcomes: []StageOutcome{ { Entity: entityExitpoint, @@ -2202,9 +2263,18 @@ func TestExecuteExitpointStage(t *testing.T) { }, expectedResponse: &openrtb2.BidResponse{ID: "test-id"}, expectedResponseHeaders: http.Header{"Content-Type": []string{"application/json"}}, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": {"exitpoint-ctx-1": "some-ctx-1", "exitpoint-ctx-3": "some-ctx-3"}, - "module-2": {"exitpoint-ctx-2": "some-ctx-2"}, + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("exitpoint-ctx-1", "some-ctx-1") + mc.Set("exitpoint-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("exitpoint-ctx-2", "some-ctx-2") + return mc + }(), }}, expectedStageOutcomes: []StageOutcome{ { @@ -2277,7 +2347,7 @@ func TestExecuteExitpointStage(t *testing.T) { expectedResponseHeaders: http.Header{ "Content-Type": []string{"application/json"}, }, - expectedModuleContexts: &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ + expectedModuleContexts: &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ "module-1": nil, "module-2": nil, }}, @@ -2345,12 +2415,18 @@ func TestInterStageContextCommunication(t *testing.T) { assert.Nil(t, reject, "Unexpected reject from entrypoint stage.") assert.Equal( t, - &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": { - "entrypoint-ctx-1": "some-ctx-1", - "entrypoint-ctx-3": "some-ctx-3", - }, - "module-2": {"entrypoint-ctx-2": "some-ctx-2"}, + &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + return mc + }(), }}, exec.moduleContexts, "Wrong module contexts after executing entrypoint hook.", @@ -2359,83 +2435,99 @@ func TestInterStageContextCommunication(t *testing.T) { // test that context added at the raw-auction stage merged with existing module contexts _, reject = exec.ExecuteRawAuctionStage(body) assert.Nil(t, reject, "Unexpected reject from raw-auction stage.") - assert.Equal(t, &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": { - "entrypoint-ctx-1": "some-ctx-1", - "entrypoint-ctx-3": "some-ctx-3", - "raw-auction-ctx-1": "some-ctx-1", - "raw-auction-ctx-3": "some-ctx-3", - }, - "module-2": { - "entrypoint-ctx-2": "some-ctx-2", - "raw-auction-ctx-2": "some-ctx-2", - }, + assert.Equal(t, &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + mc.Set("raw-auction-ctx-1", "some-ctx-1") + mc.Set("raw-auction-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + mc.Set("raw-auction-ctx-2", "some-ctx-2") + return mc + }(), }}, exec.moduleContexts, "Wrong module contexts after executing raw-auction hook.") // test that context added at the processed-auction stage merged with existing module contexts err = exec.ExecuteProcessedAuctionStage(&openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{}}) assert.Nil(t, err, "Unexpected reject from processed-auction stage.") - assert.Equal(t, &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": { - "entrypoint-ctx-1": "some-ctx-1", - "entrypoint-ctx-3": "some-ctx-3", - "raw-auction-ctx-1": "some-ctx-1", - "raw-auction-ctx-3": "some-ctx-3", - "processed-auction-ctx-1": "some-ctx-1", - "processed-auction-ctx-3": "some-ctx-3", - }, - "module-2": { - "entrypoint-ctx-2": "some-ctx-2", - "raw-auction-ctx-2": "some-ctx-2", - "processed-auction-ctx-2": "some-ctx-2", - }, + assert.Equal(t, &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + mc.Set("raw-auction-ctx-1", "some-ctx-1") + mc.Set("raw-auction-ctx-3", "some-ctx-3") + mc.Set("processed-auction-ctx-1", "some-ctx-1") + mc.Set("processed-auction-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + mc.Set("raw-auction-ctx-2", "some-ctx-2") + mc.Set("processed-auction-ctx-2", "some-ctx-2") + return mc + }(), }}, exec.moduleContexts, "Wrong module contexts after executing processed-auction hook.") // test that context added at the raw bidder response stage merged with existing module contexts reject = exec.ExecuteRawBidderResponseStage(&adapters.BidderResponse{}, "some-bidder") assert.Nil(t, reject, "Unexpected reject from raw-bidder-response stage.") - assert.Equal(t, &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": { - "entrypoint-ctx-1": "some-ctx-1", - "entrypoint-ctx-3": "some-ctx-3", - "raw-auction-ctx-1": "some-ctx-1", - "raw-auction-ctx-3": "some-ctx-3", - "processed-auction-ctx-1": "some-ctx-1", - "processed-auction-ctx-3": "some-ctx-3", - "raw-bidder-response-ctx-1": "some-ctx-1", - "raw-bidder-response-ctx-3": "some-ctx-3", - }, - "module-2": { - "entrypoint-ctx-2": "some-ctx-2", - "raw-auction-ctx-2": "some-ctx-2", - "processed-auction-ctx-2": "some-ctx-2", - "raw-bidder-response-ctx-2": "some-ctx-2", - }, + assert.Equal(t, &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + mc.Set("raw-auction-ctx-1", "some-ctx-1") + mc.Set("raw-auction-ctx-3", "some-ctx-3") + mc.Set("processed-auction-ctx-1", "some-ctx-1") + mc.Set("processed-auction-ctx-3", "some-ctx-3") + mc.Set("raw-bidder-response-ctx-1", "some-ctx-1") + mc.Set("raw-bidder-response-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + mc.Set("raw-auction-ctx-2", "some-ctx-2") + mc.Set("processed-auction-ctx-2", "some-ctx-2") + mc.Set("raw-bidder-response-ctx-2", "some-ctx-2") + return mc + }(), }}, exec.moduleContexts, "Wrong module contexts after executing raw-bidder-response hook.") // test that context added at the auction-response stage merged with existing module contexts exec.ExecuteAuctionResponseStage(&openrtb2.BidResponse{}) assert.Nil(t, reject, "Unexpected reject from raw-auction stage.") - assert.Equal(t, &moduleContexts{ctxs: map[string]hookstage.ModuleContext{ - "module-1": { - "entrypoint-ctx-1": "some-ctx-1", - "entrypoint-ctx-3": "some-ctx-3", - "raw-auction-ctx-1": "some-ctx-1", - "raw-auction-ctx-3": "some-ctx-3", - "processed-auction-ctx-1": "some-ctx-1", - "processed-auction-ctx-3": "some-ctx-3", - "raw-bidder-response-ctx-1": "some-ctx-1", - "raw-bidder-response-ctx-3": "some-ctx-3", - "auction-response-ctx-1": "some-ctx-1", - "auction-response-ctx-3": "some-ctx-3", - }, - "module-2": { - "entrypoint-ctx-2": "some-ctx-2", - "raw-auction-ctx-2": "some-ctx-2", - "processed-auction-ctx-2": "some-ctx-2", - "raw-bidder-response-ctx-2": "some-ctx-2", - "auction-response-ctx-2": "some-ctx-2", - }, + assert.Equal(t, &moduleContexts{ctxs: map[string]*hookstage.ModuleContext{ + "module-1": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-1", "some-ctx-1") + mc.Set("entrypoint-ctx-3", "some-ctx-3") + mc.Set("raw-auction-ctx-1", "some-ctx-1") + mc.Set("raw-auction-ctx-3", "some-ctx-3") + mc.Set("processed-auction-ctx-1", "some-ctx-1") + mc.Set("processed-auction-ctx-3", "some-ctx-3") + mc.Set("raw-bidder-response-ctx-1", "some-ctx-1") + mc.Set("raw-bidder-response-ctx-3", "some-ctx-3") + mc.Set("auction-response-ctx-1", "some-ctx-1") + mc.Set("auction-response-ctx-3", "some-ctx-3") + return mc + }(), + "module-2": func() *hookstage.ModuleContext { + mc := hookstage.NewModuleContext() + mc.Set("entrypoint-ctx-2", "some-ctx-2") + mc.Set("raw-auction-ctx-2", "some-ctx-2") + mc.Set("processed-auction-ctx-2", "some-ctx-2") + mc.Set("raw-bidder-response-ctx-2", "some-ctx-2") + mc.Set("auction-response-ctx-2", "some-ctx-2") + return mc + }(), }}, exec.moduleContexts, "Wrong module contexts after executing auction-response hook.") } diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go index cb3c95b9d1..a5857157d5 100644 --- a/hooks/hookexecution/mocks_test.go +++ b/hooks/hookexecution/mocks_test.go @@ -201,42 +201,50 @@ type mockModuleContextHook struct { } func (e mockModuleContextHook) HandleEntrypointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.EntrypointPayload) (hookstage.HookResult[hookstage.EntrypointPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.EntrypointPayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleRawAuctionHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.RawAuctionRequestPayload) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.RawAuctionRequestPayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleProcessedAuctionHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ProcessedAuctionRequestPayload) (hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleBidderRequestHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.BidderRequestPayload) (hookstage.HookResult[hookstage.BidderRequestPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.BidderRequestPayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleRawBidderResponseHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.RawBidderResponsePayload) (hookstage.HookResult[hookstage.RawBidderResponsePayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.RawBidderResponsePayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleAllProcessedBidResponsesHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.AllProcessedBidResponsesPayload) (hookstage.HookResult[hookstage.AllProcessedBidResponsesPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.AllProcessedBidResponsesPayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleAuctionResponseHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.AuctionResponsePayload) (hookstage.HookResult[hookstage.AuctionResponsePayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.AuctionResponsePayload]{ModuleContext: miCtx.ModuleContext}, nil } func (e mockModuleContextHook) HandleExitpointHook(_ context.Context, miCtx hookstage.ModuleInvocationContext, _ hookstage.ExitpointPayload) (hookstage.HookResult[hookstage.ExitpointPayload], error) { - miCtx.ModuleContext = map[string]interface{}{e.key: e.val} + miCtx.ModuleContext = hookstage.NewModuleContext() + miCtx.ModuleContext.Set(e.key, e.val) return hookstage.HookResult[hookstage.ExitpointPayload]{ModuleContext: miCtx.ModuleContext}, nil } diff --git a/hooks/hookstage/invocation.go b/hooks/hookstage/invocation.go index ee2f2ec89a..b0b1c00089 100644 --- a/hooks/hookstage/invocation.go +++ b/hooks/hookstage/invocation.go @@ -2,6 +2,8 @@ package hookstage import ( "encoding/json" + "maps" + "sync" "github.com/prebid/prebid-server/v4/hooks/hookanalytics" ) @@ -16,7 +18,7 @@ type HookResult[T any] struct { Warnings []string DebugMessages []string AnalyticsTags hookanalytics.Analytics - ModuleContext ModuleContext // holds values that the module wants to pass to itself at later stages + ModuleContext *ModuleContext // holds values that the module wants to pass to itself at later stages } // ModuleInvocationContext holds data passed to the module hook during invocation. @@ -28,11 +30,77 @@ type ModuleInvocationContext struct { // Endpoint represents the path of the current endpoint. Endpoint string // ModuleContext holds values that the module passes to itself from the previous stages. - ModuleContext ModuleContext + ModuleContext *ModuleContext // HookImplCode is the hook_impl_code for a module instance to differentiate between multiple hooks HookImplCode string } // ModuleContext holds arbitrary data passed between module hooks at different stages. // We use interface as we do not know exactly how the modules will use their inner context. -type ModuleContext map[string]interface{} +type ModuleContext struct { + sync.RWMutex + data map[string]any +} + +// NewModuleContext creates a new module context +func NewModuleContext() *ModuleContext { + moduleContext := ModuleContext{ + data: make(map[string]any), + } + return &moduleContext +} + +// Get retrieves a value from the module context with read lock +func (mc *ModuleContext) Get(key string) (any, bool) { + if mc == nil { + return nil, false + } + mc.RLock() + defer mc.RUnlock() + if mc.data == nil { + return nil, false + } + val, ok := mc.data[key] + return val, ok +} + +// Set stores a value in the module context with write lock +func (mc *ModuleContext) Set(key string, value any) { + if mc == nil { + return + } + mc.Lock() + defer mc.Unlock() + if mc.data == nil { + mc.data = make(map[string]any) + } + mc.data[key] = value +} + +// GetAll returns a copy of all data in the context +func (mc *ModuleContext) GetAll() map[string]any { + if mc == nil { + return nil + } + mc.RLock() + defer mc.RUnlock() + if mc.data == nil { + return nil + } + result := make(map[string]any, len(mc.data)) + maps.Copy(result, mc.data) + return result +} + +// SetAll merges the provided data into the module context +func (mc *ModuleContext) SetAll(data map[string]any) { + if mc == nil { + return + } + mc.Lock() + defer mc.Unlock() + if mc.data == nil { + mc.data = make(map[string]any, len(data)) + } + maps.Copy(mc.data, data) +} diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go index 511b85960b..9599e43de1 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go @@ -57,16 +57,18 @@ func merge(val1, val2 []stringEvidence) []stringEvidence { return evidence } -func (x *defaultEvidenceExtractor) extract(ctx hookstage.ModuleContext) ([]onpremise.Evidence, string, error) { +func (x *defaultEvidenceExtractor) extract(ctx *hookstage.ModuleContext) ([]onpremise.Evidence, string, error) { if ctx == nil { return nil, "", errors.New("context is nil") } - suaStrings, err := x.getEvidenceStrings(ctx[evidenceFromSuaCtxKey]) + evidenceFromSuaCtx, _ := ctx.Get(evidenceFromSuaCtxKey) + suaStrings, err := x.getEvidenceStrings(evidenceFromSuaCtx) if err != nil { return nil, "", fmt.Errorf("error extracting sua evidence: %w", err) } - headerString, err := x.getEvidenceStrings(ctx[evidenceFromHeadersCtxKey]) + evidenceFromHeadersCtx, _ := ctx.Get(evidenceFromHeadersCtxKey) + headerString, err := x.getEvidenceStrings(evidenceFromHeadersCtx) if err != nil { return nil, "", fmt.Errorf("error extracting header evidence: %w", err) } diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go index 7e2aa6616d..8c183af559 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor_test.go @@ -129,7 +129,7 @@ func TestExtract(t *testing.T) { tests := []struct { name string - ctx hookstage.ModuleContext + ctx *hookstage.ModuleContext wantEvidenceCount int wantUserAgent string wantError bool @@ -141,96 +141,120 @@ func TestExtract(t *testing.T) { }, { name: "empty", - ctx: hookstage.ModuleContext{ - evidenceFromSuaCtxKey: []stringEvidence{}, - evidenceFromHeadersCtxKey: []stringEvidence{}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{}) + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{}) + return ctx + }(), wantEvidenceCount: 0, wantUserAgent: "", }, { name: "from_headers", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{uaEvidence1}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{uaEvidence1}) + return ctx + }(), wantEvidenceCount: 1, wantUserAgent: "uav1", }, { name: "from_headers_no_user_agent", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{evidence1}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{evidence1}) + return ctx + }(), wantError: true, }, { name: "from_sua", - ctx: hookstage.ModuleContext{ - evidenceFromSuaCtxKey: []stringEvidence{uaEvidence1}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{uaEvidence1}) + return ctx + }(), wantEvidenceCount: 1, wantUserAgent: "uav1", }, { name: "from_sua_no_user_agent", - ctx: hookstage.ModuleContext{ - evidenceFromSuaCtxKey: []stringEvidence{evidence1}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{evidence1}) + return ctx + }(), wantError: true, }, { name: "from_headers_error", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: "bad value", - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, "bad value") + return ctx + }(), wantError: true, }, { name: "from_sua_error", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{}, - evidenceFromSuaCtxKey: "bad value", - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{}) + ctx.Set(evidenceFromSuaCtxKey, "bad value") + return ctx + }(), wantError: true, }, { name: "from_sua_and_headers", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{uaEvidence1}, - evidenceFromSuaCtxKey: []stringEvidence{evidence1}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{uaEvidence1}) + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{evidence1}) + return ctx + }(), wantEvidenceCount: 2, wantUserAgent: "uav1", }, { name: "from_sua_and_headers_sua_can_overwrite_if_ua_present", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{uaEvidence1}, - evidenceFromSuaCtxKey: []stringEvidence{uaEvidence2}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{uaEvidence1}) + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{uaEvidence2}) + return ctx + }(), wantEvidenceCount: 1, wantUserAgent: "uav2", }, { name: "empty_string_values", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{emptyEvidence}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{emptyEvidence}) + return ctx + }(), wantError: true, }, { name: "empty_sua_values", - ctx: hookstage.ModuleContext{ - evidenceFromSuaCtxKey: []stringEvidence{emptyEvidence}, - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromSuaCtxKey, []stringEvidence{emptyEvidence}) + return ctx + }(), wantError: true, }, { name: "mixed_valid_and_invalid", - ctx: hookstage.ModuleContext{ - evidenceFromHeadersCtxKey: []stringEvidence{uaEvidence1}, - evidenceFromSuaCtxKey: "bad value", - }, + ctx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(evidenceFromHeadersCtxKey, []stringEvidence{uaEvidence1}) + ctx.Set(evidenceFromSuaCtxKey, "bad value") + return ctx + }(), wantError: true, }, } diff --git a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go index f1429ef7e1..996845a2f0 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go +++ b/modules/fiftyonedegrees/devicedetection/hook_auction_entrypoint.go @@ -18,10 +18,10 @@ func handleAuctionEntryPointRequestHook(cfg config, payload hookstage.Entrypoint evidenceFromSua := evidenceExtractor.fromSuaPayload(payload.Body) // create a Module context and set the evidence from headers, evidence from sua and dd enabled flag - moduleContext := make(hookstage.ModuleContext) - moduleContext[evidenceFromHeadersCtxKey] = evidenceFromHeaders - moduleContext[evidenceFromSuaCtxKey] = evidenceFromSua - moduleContext[ddEnabledCtxKey] = true + moduleContext := hookstage.NewModuleContext() + moduleContext.Set(evidenceFromHeadersCtxKey, evidenceFromHeaders) + moduleContext.Set(evidenceFromSuaCtxKey, evidenceFromSua) + moduleContext.Set(ddEnabledCtxKey, true) return hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: moduleContext, diff --git a/modules/fiftyonedegrees/devicedetection/module.go b/modules/fiftyonedegrees/devicedetection/module.go index 72c0f60d94..4dddc577f4 100644 --- a/modules/fiftyonedegrees/devicedetection/module.go +++ b/modules/fiftyonedegrees/devicedetection/module.go @@ -83,7 +83,7 @@ type accountValidator interface { type evidenceExtractor interface { fromHeaders(request *http.Request, httpHeaderKeys []dd.EvidenceKey) []stringEvidence fromSuaPayload(payload []byte) []stringEvidence - extract(ctx hookstage.ModuleContext) ([]onpremise.Evidence, string, error) + extract(ctx *hookstage.ModuleContext) ([]onpremise.Evidence, string, error) } func (m Module) HandleEntrypointHook( diff --git a/modules/fiftyonedegrees/devicedetection/module_test.go b/modules/fiftyonedegrees/devicedetection/module_test.go index 5566f8e25a..7f757cd42d 100644 --- a/modules/fiftyonedegrees/devicedetection/module_test.go +++ b/modules/fiftyonedegrees/devicedetection/module_test.go @@ -44,7 +44,7 @@ func (m *mockEvidenceExtractor) fromSuaPayload(payload []byte) []stringEvidence return args.Get(0).([]stringEvidence) } -func (m *mockEvidenceExtractor) extract(ctx hookstage.ModuleContext) ([]onpremise.Evidence, string, error) { +func (m *mockEvidenceExtractor) extract(ctx *hookstage.ModuleContext) ([]onpremise.Evidence, string, error) { args := m.Called(ctx) res := args.Get(0) @@ -131,16 +131,18 @@ func TestHandleEntrypointHookAccountAllowed(t *testing.T) { result, err := module.HandleEntrypointHook(nil, hookstage.ModuleInvocationContext{}, hookstage.EntrypointPayload{}) assert.NoError(t, err) + evidenceFromHeadersCtx, _ := result.ModuleContext.Get(evidenceFromHeadersCtxKey) assert.Equal( - t, result.ModuleContext[evidenceFromHeadersCtxKey], []stringEvidence{{ + t, evidenceFromHeadersCtx, []stringEvidence{{ Prefix: "123", Key: "key", Value: "val", }}, ) + evidenceFromSuaCtx, _ := result.ModuleContext.Get(evidenceFromSuaCtxKey) assert.Equal( - t, result.ModuleContext[evidenceFromSuaCtxKey], []stringEvidence{{ + t, evidenceFromSuaCtx, []stringEvidence{{ Prefix: "123", Key: "User-Agent", Value: "ua", @@ -179,9 +181,8 @@ func TestHandleRawAuctionHookExtractError(t *testing.T) { accountValidator: &mockValidator, } - mctx := make(hookstage.ModuleContext) - - mctx[ddEnabledCtxKey] = true + mctx := hookstage.NewModuleContext() + mctx.Set(ddEnabledCtxKey, true) result, err := module.HandleRawAuctionHook( context.TODO(), hookstage.ModuleInvocationContext{ @@ -280,8 +281,8 @@ func TestHandleRawAuctionHookEnrichment(t *testing.T) { accountValidator: &mockValidator, } - mctx := make(hookstage.ModuleContext) - mctx[ddEnabledCtxKey] = true + mctx := hookstage.NewModuleContext() + mctx.Set(ddEnabledCtxKey, true) result, err := module.HandleRawAuctionHook( nil, hookstage.ModuleInvocationContext{ @@ -483,8 +484,8 @@ func TestHandleRawAuctionHookEnrichmentWithErrors(t *testing.T) { accountValidator: &mockValidator, } - mctx := make(hookstage.ModuleContext) - mctx[ddEnabledCtxKey] = true + mctx := hookstage.NewModuleContext() + mctx.Set(ddEnabledCtxKey, true) result, err := module.HandleRawAuctionHook( nil, hookstage.ModuleInvocationContext{ diff --git a/modules/prebid/ortb2blocking/hook_bidderrequest.go b/modules/prebid/ortb2blocking/hook_bidderrequest.go index 14abbec43a..9542777ae0 100644 --- a/modules/prebid/ortb2blocking/hook_bidderrequest.go +++ b/modules/prebid/ortb2blocking/hook_bidderrequest.go @@ -47,7 +47,10 @@ func handleBidderRequestHook( updateCatTax(cfg, payload, &blockingAttributes, &changeSet) result.ChangeSet = changeSet - result.ModuleContext = hookstage.ModuleContext{payload.Bidder: blockingAttributes} + if result.ModuleContext == nil { + result.ModuleContext = hookstage.NewModuleContext() + } + result.ModuleContext.Set(payload.Bidder, blockingAttributes) return result, nil } diff --git a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go index deeb3b0296..cbdae93735 100644 --- a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go +++ b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go @@ -15,10 +15,10 @@ import ( func handleRawBidderResponseHook( cfg config, payload hookstage.RawBidderResponsePayload, - moduleCtx hookstage.ModuleContext, + moduleCtx *hookstage.ModuleContext, ) (result hookstage.HookResult[hookstage.RawBidderResponsePayload], err error) { bidder := payload.Bidder - blockAttrsVal, ok := moduleCtx[bidder] + blockAttrsVal, ok := moduleCtx.Get(bidder) if !ok { // if there are no blocking attributes for this bidder just pass empty blockingAttributes for further processing // other values from config must still be checked diff --git a/modules/prebid/ortb2blocking/module_test.go b/modules/prebid/ortb2blocking/module_test.go index 7d002d29c8..85be537bb6 100644 --- a/modules/prebid/ortb2blocking/module_test.go +++ b/modules/prebid/ortb2blocking/module_test.go @@ -343,8 +343,9 @@ func TestHandleBidderRequestHook(t *testing.T) { }, }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ - ModuleContext: map[string]interface{}{ - bidder: blockingAttributes{ + ModuleContext: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{ bAdv: []string{bAdvA, bAdvB}, bApp: []string{bApp3}, bCat: []string{bCat1, bCat2, bCat3, bCat4}, @@ -357,8 +358,9 @@ func TestHandleBidderRequestHook(t *testing.T) { "ImpID2": toInt([]adcom1.CreativeAttribute{bAttr1, bAttr8, bAttr9, bAttr10}), }, catTax: catTax, - }, - }, + }) + return mctx + }(), Warnings: []string{ // multiple warnings may be added (per condition) "More than one condition matches request. Bidder: appnexus, request media types: audio, banner, native, video", @@ -389,12 +391,14 @@ func TestHandleBidderRequestHook(t *testing.T) { }, }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ - ModuleContext: map[string]interface{}{ - bidder: blockingAttributes{ + ModuleContext: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{ bAdv: []string{bAdvA, bAdvB, bAdvC}, bAttr: map[string][]int{}, - }, - }, + }) + return mctx + }(), }, expectedError: nil, }, @@ -439,9 +443,13 @@ func TestHandleBidderRequestHook(t *testing.T) { }, }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ - ModuleContext: map[string]interface{}{bidder: blockingAttributes{ - bAttr: map[string][]int{}, - }}, + ModuleContext: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{ + bAttr: map[string][]int{}, + }) + return mctx + }(), }, expectedError: nil, }, @@ -459,9 +467,13 @@ func TestHandleBidderRequestHook(t *testing.T) { Imp: []openrtb2.Imp{{ID: "ImpID1", Video: &openrtb2.Video{}}}, }, expectedHookResult: hookstage.HookResult[hookstage.BidderRequestPayload]{ - ModuleContext: map[string]interface{}{bidder: blockingAttributes{ - bAttr: map[string][]int{}, - }}, + ModuleContext: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{ + bAttr: map[string][]int{}, + }) + return mctx + }(), }, expectedError: nil, }, @@ -579,7 +591,7 @@ func TestHandleBidderRequestHook(t *testing.T) { hookstage.ModuleInvocationContext{ AccountConfig: test.config, Endpoint: hookexecution.EndpointAuction, - ModuleContext: map[string]interface{}{}, + ModuleContext: hookstage.NewModuleContext(), }, payload, ) @@ -605,7 +617,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { description string payload hookstage.RawBidderResponsePayload config json.RawMessage - moduleCtx hookstage.ModuleContext + moduleCtx *hookstage.ModuleContext expectedBids []*adapters.TypedBid expectedHookResult hookstage.HookResult[hookstage.RawBidderResponsePayload] expectedError error @@ -655,7 +667,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ADomain: []string{"foo"}, ImpID: impID1}, }, }, - moduleCtx: map[string]interface{}{bidder: "boo"}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, "boo") + return mctx + }(), expectedError: hookexecution.NewFailure("could not cast blocking attributes for bidder `appnexus`, module context has incorrect data"), }, { @@ -676,7 +692,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bAdv: []string{"forbidden_domain"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bAdv: []string{"forbidden_domain"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -724,7 +744,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{"other-bidder": blockingAttributes{bAdv: []string{"forbidden_domain"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set("other-bidder", blockingAttributes{bAdv: []string{"forbidden_domain"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -767,7 +791,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bAdv: []string{"forbidden_domain"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bAdv: []string{"forbidden_domain"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -810,7 +838,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bAdv: []string{"forbidden_domain"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bAdv: []string{"forbidden_domain"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -850,7 +882,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -898,7 +934,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -941,7 +981,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bAdv: []string{"forbidden_domain"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bAdv: []string{"forbidden_domain"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -1062,7 +1106,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", Cat: []string{"moto"}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bCat: []string{"fishing"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bCat: []string{"fishing"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -1188,7 +1236,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", CatTax: 2, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{catTax: 2}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{catTax: 2}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -1277,7 +1329,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", Bundle: "allowed_bundle", ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bApp: []string{"forbidden_bundle"}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bApp: []string{"forbidden_bundle"}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -1376,7 +1432,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bid: &openrtb2.Bid{ID: "2", Attr: []adcom1.CreativeAttribute{2}, ImpID: impID2}, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{bAttr: map[string][]int{impID1: {1}}}}, + moduleCtx: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set(bidder, blockingAttributes{bAttr: map[string][]int{impID1: {1}}}) + return mctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ @@ -1499,13 +1559,17 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, }, - moduleCtx: map[string]interface{}{bidder: blockingAttributes{ - bAdv: []string{"forbidden_domain"}, - bCat: []string{"fishing"}, - catTax: 2, - bApp: []string{"forbidden_bundle"}, - bAttr: map[string][]int{impID1: {1}}}, - }, + moduleCtx: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(bidder, blockingAttributes{ + bAdv: []string{"forbidden_domain"}, + bCat: []string{"fishing"}, + catTax: 2, + bApp: []string{"forbidden_bundle"}, + bAttr: map[string][]int{impID1: {1}}, + }) + return ctx + }(), expectedHookResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{ AnalyticsTags: hookanalytics.Analytics{ Activities: []hookanalytics.Activity{ diff --git a/modules/scientiamobile/wurfl_devicedetection/module.go b/modules/scientiamobile/wurfl_devicedetection/module.go index 53bb26e74d..7cbf8d3a6d 100644 --- a/modules/scientiamobile/wurfl_devicedetection/module.go +++ b/modules/scientiamobile/wurfl_devicedetection/module.go @@ -75,8 +75,8 @@ func (m Module) HandleEntrypointHook(ctx context.Context, invocationCtx hookstag header[k] = payload.Request.Header.Get(k) } } - moduleContext := make(hookstage.ModuleContext) - moduleContext[wurflHeaderCtxKey] = header + moduleContext := hookstage.NewModuleContext() + moduleContext.Set(wurflHeaderCtxKey, header) result.ModuleContext = moduleContext return result, nil @@ -101,7 +101,11 @@ func (m Module) HandleRawAuctionHook( return result, nil } - rawHeaders, ok := invocationCtx.ModuleContext[wurflHeaderCtxKey].(map[string]string) + headers, ok := invocationCtx.ModuleContext.Get(wurflHeaderCtxKey) + if !ok { + return result, hookexecution.NewFailure("invalid module context type") + } + rawHeaders, ok := headers.(map[string]string) if !ok { return result, hookexecution.NewFailure("invalid module context type") } diff --git a/modules/scientiamobile/wurfl_devicedetection/module_test.go b/modules/scientiamobile/wurfl_devicedetection/module_test.go index 64aaefe7fd..8dc0ee48ee 100644 --- a/modules/scientiamobile/wurfl_devicedetection/module_test.go +++ b/modules/scientiamobile/wurfl_devicedetection/module_test.go @@ -150,7 +150,8 @@ func TestHandleEntrypointHook(t *testing.T) { } else { assert.NoError(t, err) assert.NotNil(t, result.ModuleContext) - assert.Equal(t, tc.expectedModuleCtx[wurflHeaderCtxKey], result.ModuleContext[wurflHeaderCtxKey]) + headers, _ := result.ModuleContext.Get(wurflHeaderCtxKey) + assert.Equal(t, tc.expectedModuleCtx[wurflHeaderCtxKey], headers) } }) } @@ -184,11 +185,13 @@ func TestHandleRawAuctionHook(t *testing.T) { extCaps: false, }, invocationCtx: hookstage.ModuleInvocationContext{ - ModuleContext: hookstage.ModuleContext{ - wurflHeaderCtxKey: map[string]string{ + ModuleContext: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(wurflHeaderCtxKey, map[string]string{ "User-Agent": "Mozilla/5.0", - }, - }, + }) + return ctx + }(), }, payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), expectedErr: false, @@ -242,11 +245,13 @@ func TestHandleRawAuctionHook(t *testing.T) { extCaps: true, }, invocationCtx: hookstage.ModuleInvocationContext{ - ModuleContext: hookstage.ModuleContext{ - wurflHeaderCtxKey: map[string]string{ + ModuleContext: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(wurflHeaderCtxKey, map[string]string{ "User-Agent": "Mozilla/5.0", - }, - }, + }) + return ctx + }(), }, payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), expectedErr: false, @@ -288,11 +293,13 @@ func TestHandleRawAuctionHook(t *testing.T) { extCaps: true, }, invocationCtx: hookstage.ModuleInvocationContext{ - ModuleContext: hookstage.ModuleContext{ - wurflHeaderCtxKey: map[string]string{ + ModuleContext: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(wurflHeaderCtxKey, map[string]string{ "User-Agent": "Mozilla/5.0", - }, - }, + }) + return ctx + }(), }, payload: []byte(`{"device":{"ua":"Mozilla/5.0", "ext": {"test": 1}}}`), expectedErr: false, @@ -328,11 +335,13 @@ func TestHandleRawAuctionHook(t *testing.T) { extCaps: false, }, invocationCtx: hookstage.ModuleInvocationContext{ - ModuleContext: hookstage.ModuleContext{ - wurflHeaderCtxKey: map[string]string{ + ModuleContext: func() *hookstage.ModuleContext { + ctx := hookstage.NewModuleContext() + ctx.Set(wurflHeaderCtxKey, map[string]string{ "User-Agent": "Mozilla/5.0", - }, - }, + }) + return ctx + }(), }, payload: []byte(`{"device":{"ua":"Mozilla/5.0"}}`), expectedErr: false, diff --git a/modules/scope3/rtd/module.go b/modules/scope3/rtd/module.go index ab4ac3b459..9ad4e61702 100644 --- a/modules/scope3/rtd/module.go +++ b/modules/scope3/rtd/module.go @@ -186,11 +186,11 @@ func (m *Module) HandleEntrypointHook( miCtx hookstage.ModuleInvocationContext, payload hookstage.EntrypointPayload, ) (hookstage.HookResult[hookstage.EntrypointPayload], error) { + moduleContext := hookstage.NewModuleContext() + moduleContext.Set(asyncRequestKey, m.NewAsyncRequest(payload.Request)) // Initialize module context with sync.Map for thread-safe segment storage return hookstage.HookResult[hookstage.EntrypointPayload]{ - ModuleContext: hookstage.ModuleContext{ - asyncRequestKey: m.NewAsyncRequest(payload.Request), - }, + ModuleContext: moduleContext, }, nil } @@ -203,7 +203,23 @@ func (m *Module) HandleProcessedAuctionHook( var ret hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload] analyticsNamePrefix := "HandleProcessedAuctionHook." - asyncRequest, ok := miCtx.ModuleContext[asyncRequestKey].(*AsyncRequest) + request, ok := miCtx.ModuleContext.Get(asyncRequestKey) + if !ok { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + asyncRequestKey, + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": "failed to get async request from module context"}, + }}, + }}, + } + return ret, nil + } + + asyncRequest, ok := request.(*AsyncRequest) if !ok { // Log error but don't fail the auction ret.AnalyticsTags = hookanalytics.Analytics{ @@ -233,7 +249,24 @@ func (m *Module) HandleAuctionResponseHook( ) (hookstage.HookResult[hookstage.AuctionResponsePayload], error) { analyticsNamePrefix := "HandleAuctionResponseHook." var ret hookstage.HookResult[hookstage.AuctionResponsePayload] - asyncRequest, ok := miCtx.ModuleContext[asyncRequestKey].(*AsyncRequest) + + request, ok := miCtx.ModuleContext.Get(asyncRequestKey) + if !ok { + // Log error but don't fail the auction + ret.AnalyticsTags = hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{{ + Name: analyticsNamePrefix + asyncRequestKey, + Status: hookanalytics.ActivityStatusError, + Results: []hookanalytics.Result{{ + Status: hookanalytics.ResultStatusError, + Values: map[string]interface{}{"error": "failed to get async request from module context"}, + }}, + }}, + } + return ret, nil + } + + asyncRequest, ok := request.(*AsyncRequest) if !ok { // Log error but don't fail the auction ret.AnalyticsTags = hookanalytics.Analytics{ diff --git a/modules/scope3/rtd/module_test.go b/modules/scope3/rtd/module_test.go index a9339d3242..6b40353cf0 100644 --- a/modules/scope3/rtd/module_test.go +++ b/modules/scope3/rtd/module_test.go @@ -83,16 +83,19 @@ func TestHandleEntrypointHook(t *testing.T) { result, err := module.HandleEntrypointHook(ctx, miCtx, payload) assert.NoError(t, err) - assert.NotNil(t, result.ModuleContext[asyncRequestKey]) + asyncRequest, _ := result.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) } func TestHandleAuctionResponseHook_NoSegments(t *testing.T) { module := &Module{} ctx := context.Background() miCtx := hookstage.ModuleInvocationContext{ - ModuleContext: hookstage.ModuleContext{ - "segments": &sync.Map{}, - }, + ModuleContext: func() *hookstage.ModuleContext { + mctx := hookstage.NewModuleContext() + mctx.Set("segments", &sync.Map{}) + return mctx + }(), } payload := hookstage.AuctionResponsePayload{} @@ -256,7 +259,8 @@ func TestScope3APIIntegrationNoSegments(t *testing.T) { // Test entrypoint hook entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) require.NoError(t, err) - assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + asyncRequest, _ := entrypointResult.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) payload := hookstage.ProcessedAuctionRequestPayload{ Request: &openrtb_ext.RequestWrapper{ @@ -359,7 +363,8 @@ func TestScope3APIIntegrationWithTargeting(t *testing.T) { // Test entrypoint hook entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) require.NoError(t, err) - assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + asyncRequest, _ := entrypointResult.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) // Create test request payload width := int64(300) @@ -541,7 +546,8 @@ func TestScope3APIIntegrationWithTargetingNoScope3Section(t *testing.T) { // Test entrypoint hook entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) require.NoError(t, err) - assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + asyncRequest, _ := entrypointResult.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) // Create test request payload width := int64(300) @@ -684,7 +690,8 @@ func TestScope3APIIntegrationWithExistingPrebidTargeting(t *testing.T) { // Test entrypoint hook entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) require.NoError(t, err) - assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + asyncRequest, _ := entrypointResult.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) // Create test request payload width := int64(300) @@ -794,7 +801,8 @@ func TestScope3APIIntegrationWithExistingPrebidNoTargeting(t *testing.T) { // Test entrypoint hook entrypointResult, err := module.HandleEntrypointHook(ctx, hookstage.ModuleInvocationContext{}, getTestEntrypointPayload(t)) require.NoError(t, err) - assert.NotNil(t, entrypointResult.ModuleContext[asyncRequestKey]) + asyncRequest, _ := entrypointResult.ModuleContext.Get(asyncRequestKey) + assert.NotNil(t, asyncRequest) // Create test request payload width := int64(300) From 3c20de6642ba1349a433d4ae7e1ba0d28200267d Mon Sep 17 00:00:00 2001 From: tomaszbmf <142428312+tomaszbmf@users.noreply.github.com> Date: Tue, 26 May 2026 16:28:40 +0200 Subject: [PATCH 221/272] MobileFuse: Update to support OpenRTB MType (#4719) --- adapters/mobilefuse/mobilefuse.go | 42 +++++++++---------- .../exemplary/multi-imps-multi-format.json | 9 ++-- .../mobilefusetest/exemplary/multi-imps.json | 9 ++-- .../exemplary/simple-banner.json | 9 ++-- .../exemplary/simple-native.json | 9 ++-- .../exemplary/simple-video.json | 9 ++-- 6 files changed, 34 insertions(+), 53 deletions(-) diff --git a/adapters/mobilefuse/mobilefuse.go b/adapters/mobilefuse/mobilefuse.go index a7f50dc0b0..1bcc20b66d 100644 --- a/adapters/mobilefuse/mobilefuse.go +++ b/adapters/mobilefuse/mobilefuse.go @@ -18,14 +18,6 @@ type MobileFuseAdapter struct { Endpoint string } -type ExtMf struct { - MediaType string `json:"media_type"` -} - -type BidExt struct { - Mf ExtMf `json:"mf"` -} - type ExtSkadn struct { Skadn json.RawMessage `json:"skadn"` } @@ -74,10 +66,15 @@ func (adapter *MobileFuseAdapter) MakeBids(incomingRequest *openrtb2.BidRequest, } outgoingBidResponse := adapters.NewBidderResponseWithBidsCapacity(1) - + var errors []error for _, seatbid := range incomingBidResponse.SeatBid { for i := range seatbid.Bid { - bidType := getBidType(seatbid.Bid[i]) + bidType, err := getBidType(seatbid.Bid[i]) + if err != nil { + errors = append(errors, err) + continue + } + seatbid.Bid[i].Ext = nil outgoingBidResponse.Bids = append(outgoingBidResponse.Bids, &adapters.TypedBid{ @@ -87,7 +84,7 @@ func (adapter *MobileFuseAdapter) MakeBids(incomingRequest *openrtb2.BidRequest, } } - return outgoingBidResponse, nil + return outgoingBidResponse, errors } func (adapter *MobileFuseAdapter) makeRequest(bidRequest *openrtb2.BidRequest) (*adapters.RequestData, []error) { @@ -200,18 +197,17 @@ func getValidImps(bidRequest *openrtb2.BidRequest, ext *openrtb_ext.ExtImpMobile return validImps, nil } -func getBidType(bid openrtb2.Bid) openrtb_ext.BidType { - if bid.Ext != nil { - var bidExt BidExt - err := jsonutil.Unmarshal(bid.Ext, &bidExt) - if err == nil { - if bidExt.Mf.MediaType == "video" { - return openrtb_ext.BidTypeVideo - } else if bidExt.Mf.MediaType == "native" { - return openrtb_ext.BidTypeNative - } +func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unsupported MType \"%d\" for impression ID \"%s\"", bid.MType, bid.ImpID), } } - - return openrtb_ext.BidTypeBanner } diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json index 039758bd52..1c7a770aa1 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps-multi-format.json @@ -117,11 +117,7 @@ "crid": "test-crid", "h": 50, "w": 320, - "ext": { - "mf": { - "media_type": "banner" - } - } + "mtype": 1 } ] } @@ -143,7 +139,8 @@ "adm": "some-test-ad", "crid": "test-crid", "w": 320, - "h": 50 + "h": 50, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json index 4e0206f298..bb1b6d7c30 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/multi-imps.json @@ -89,11 +89,7 @@ "crid": "test-crid", "h": 50, "w": 320, - "ext": { - "mf": { - "media_type": "banner" - } - } + "mtype": 1 } ] } @@ -116,7 +112,8 @@ "adm": "some-test-ad", "crid": "test-crid", "w": 320, - "h": 50 + "h": 50, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json index d6b70c5a28..48d9335d62 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-banner.json @@ -61,11 +61,7 @@ "crid": "test-crid", "h": 50, "w": 320, - "ext": { - "mf": { - "media_type": "banner" - } - } + "mtype": 1 } ] } @@ -88,7 +84,8 @@ "adm": "some-test-ad", "crid": "test-crid", "w": 320, - "h": 50 + "h": 50, + "mtype": 1 }, "type": "banner" } diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json index 8a075d955a..5906b37041 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-native.json @@ -51,11 +51,7 @@ "crid": "test-crid", "h": 50, "w": 320, - "ext": { - "mf": { - "media_type": "native" - } - } + "mtype": 4 } ] } @@ -77,7 +73,8 @@ "adm": "{\"native\":{\"link\":{\"url\":\"http://mfx.mobilefuse.com/openrtb\"},\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"url\":\"...\"}},{\"id\":1,\"required\":1,\"title\":{\"text\":\"custom title\"}}]}}", "crid": "test-crid", "h": 50, - "w": 320 + "w": 320, + "mtype": 4 }, "type": "native" } diff --git a/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json index 71bfdaf0fe..2dd83841b0 100644 --- a/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json +++ b/adapters/mobilefuse/mobilefusetest/exemplary/simple-video.json @@ -66,11 +66,7 @@ "crid": "test-crid", "w": 320, "h": 480, - "ext": { - "mf": { - "media_type": "video" - } - } + "mtype": 2 } ] } @@ -91,7 +87,8 @@ "adm": "some-test-ad", "crid": "test-crid", "w": 320, - "h": 480 + "h": 480, + "mtype": 2 }, "type": "video" } From b4476c2ca5353753df428745f11c299fd7534070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= <hugolm84@gmail.com> Date: Tue, 26 May 2026 16:48:34 +0200 Subject: [PATCH 222/272] Relevant Digital: Add useSourceBidderCode option (#4694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hugo Lindström <hugo.lindstrom@relevant-digital.com> --- adapters/relevantdigital/params_test.go | 3 + adapters/relevantdigital/relevantdigital.go | 21 +++ .../supplemental/useSourceBidderCode.json | 131 ++++++++++++++ .../useSourceBidderCodeDisabled.json | 129 ++++++++++++++ ...rceBidderCodeDisabledMultipleSeatBids.json | 157 +++++++++++++++++ .../useSourceBidderCodeMultipleSeatBids.json | 160 ++++++++++++++++++ openrtb_ext/imp_relevantdigital.go | 9 +- static/bidder-params/relevantdigital.json | 4 + 8 files changed, 610 insertions(+), 4 deletions(-) create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCode.json create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabled.json create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabledMultipleSeatBids.json create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeMultipleSeatBids.json diff --git a/adapters/relevantdigital/params_test.go b/adapters/relevantdigital/params_test.go index 835e1e77c8..8505e4c478 100644 --- a/adapters/relevantdigital/params_test.go +++ b/adapters/relevantdigital/params_test.go @@ -35,8 +35,11 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host" }`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": true }`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": false }`, } var invalidParams = []string{ `{"accountId": 123, "placementId" : 123, "pbsHost" : ""}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": "somethingInvalid" }`, } diff --git a/adapters/relevantdigital/relevantdigital.go b/adapters/relevantdigital/relevantdigital.go index 3286b49714..44f1ebdf3f 100644 --- a/adapters/relevantdigital/relevantdigital.go +++ b/adapters/relevantdigital/relevantdigital.go @@ -114,6 +114,11 @@ func setTMax(prebidBidRequest *openrtb2.BidRequest, pbsBufferMs int) { func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params []*openrtb_ext.ExtRelevantDigital) ([]byte, error) { bidRequestCopy := *prebidBidRequest + // Copy Imp slice so patchBidImpExt only mutates this outgoing request. + // MakeBids receives the same request and needs the original Imp[].Ext + // to read useSourceBidderCode from bidder params. + bidRequestCopy.Imp = make([]openrtb2.Imp, len(prebidBidRequest.Imp)) + copy(bidRequestCopy.Imp, prebidBidRequest.Imp) err := patchBidRequestExt(&bidRequestCopy, params[0].AccountId) if err != nil { @@ -292,6 +297,17 @@ func isSupportedMediaType(bidType openrtb_ext.BidType) error { return fmt.Errorf("bid type not supported %s", bidType) } +func useSourceBidderCode(request *openrtb2.BidRequest) bool { + if request == nil || len(request.Imp) == 0 { + return false + } + impExt, err := getImpressionExt(&request.Imp[0]) + if err != nil { + return false + } + return impExt.UseSourceBidderCode +} + func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { if adapters.IsResponseStatusCodeNoContent(responseData) { return nil, nil @@ -306,6 +322,8 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R return nil, []error{err} } + passSourceSeat := useSourceBidderCode(request) + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(response.SeatBid)) bidResponse.Currency = response.Cur var errs []error @@ -324,6 +342,9 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R Bid: &seatBid.Bid[i], BidType: bidType, } + if passSourceSeat { + b.Seat = openrtb_ext.BidderName(seatBid.Seat) + } bidResponse.Bids = append(bidResponse.Bids, b) } } diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCode.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCode.json new file mode 100644 index 0000000000..1b8e105dfe --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCode.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "accountId": "620523ae7f4bbe1691bbb815", + "pbsHost": "fakeHost", + "placementId": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817", + "useSourceBidderCode": true + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fakeHost.relevant-digital.com/openrtb2/auction", + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "ext": { + "prebid": { + "debug": false, + "storedrequest": { + "id": "620523ae7f4bbe1691bbb815" + } + }, + "relevant": { + "adapterType": "server", + "count": 1 + } + }, + "tmax": 750 + }, + "impIDs": ["div-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "seatbid": [ + { + "seat": "pubmatic", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner", + "seat": "pubmatic" + } + ] + } + ] +} diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabled.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabled.json new file mode 100644 index 0000000000..a8ab5a81c0 --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabled.json @@ -0,0 +1,129 @@ +{ + "mockBidRequest": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "accountId": "620523ae7f4bbe1691bbb815", + "pbsHost": "fakeHost", + "placementId": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fakeHost.relevant-digital.com/openrtb2/auction", + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "ext": { + "prebid": { + "debug": false, + "storedrequest": { + "id": "620523ae7f4bbe1691bbb815" + } + }, + "relevant": { + "adapterType": "server", + "count": 1 + } + }, + "tmax": 750 + }, + "impIDs": ["div-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "seatbid": [ + { + "seat": "pubmatic", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabledMultipleSeatBids.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabledMultipleSeatBids.json new file mode 100644 index 0000000000..8040c2e039 --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeDisabledMultipleSeatBids.json @@ -0,0 +1,157 @@ +{ + "mockBidRequest": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "accountId": "620523ae7f4bbe1691bbb815", + "pbsHost": "fakeHost", + "placementId": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fakeHost.relevant-digital.com/openrtb2/auction", + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "ext": { + "prebid": { + "debug": false, + "storedrequest": { + "id": "620523ae7f4bbe1691bbb815" + } + }, + "relevant": { + "adapterType": "server", + "count": 1 + } + }, + "tmax": 750 + }, + "impIDs": ["div-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "seatbid": [ + { + "seat": "pubmatic", + "bid": [ + { + "id": "bid-1", + "impid": "div-1", + "price": 0.5, + "adm": "pubmatic-ad", + "crid": "crid_1", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + }, + { + "seat": "appnexus", + "bid": [ + { + "id": "bid-2", + "impid": "div-1", + "price": 0.8, + "adm": "appnexus-ad", + "crid": "crid_2", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "div-1", + "price": 0.5, + "adm": "pubmatic-ad", + "crid": "crid_1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-2", + "impid": "div-1", + "price": 0.8, + "adm": "appnexus-ad", + "crid": "crid_2", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeMultipleSeatBids.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeMultipleSeatBids.json new file mode 100644 index 0000000000..1a0b8e2aac --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/useSourceBidderCodeMultipleSeatBids.json @@ -0,0 +1,160 @@ +{ + "mockBidRequest": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "accountId": "620523ae7f4bbe1691bbb815", + "pbsHost": "fakeHost", + "placementId": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817", + "useSourceBidderCode": true + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fakeHost.relevant-digital.com/openrtb2/auction", + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com" + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "ext": { + "prebid": { + "debug": false, + "storedrequest": { + "id": "620523ae7f4bbe1691bbb815" + } + }, + "relevant": { + "adapterType": "server", + "count": 1 + } + }, + "tmax": 750 + }, + "impIDs": ["div-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "seatbid": [ + { + "seat": "pubmatic", + "bid": [ + { + "id": "bid-1", + "impid": "div-1", + "price": 0.5, + "adm": "pubmatic-ad", + "crid": "crid_1", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + }, + { + "seat": "appnexus", + "bid": [ + { + "id": "bid-2", + "impid": "div-1", + "price": 0.8, + "adm": "appnexus-ad", + "crid": "crid_2", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "div-1", + "price": 0.5, + "adm": "pubmatic-ad", + "crid": "crid_1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner", + "seat": "pubmatic" + }, + { + "bid": { + "id": "bid-2", + "impid": "div-1", + "price": 0.8, + "adm": "appnexus-ad", + "crid": "crid_2", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner", + "seat": "appnexus" + } + ] + } + ] +} diff --git a/openrtb_ext/imp_relevantdigital.go b/openrtb_ext/imp_relevantdigital.go index ec250557c2..ccd5c201f4 100644 --- a/openrtb_ext/imp_relevantdigital.go +++ b/openrtb_ext/imp_relevantdigital.go @@ -1,8 +1,9 @@ package openrtb_ext type ExtRelevantDigital struct { - AccountId string `json:"accountId"` - PlacementId string `json:"placementId"` - Host string `json:"pbsHost"` - PbsBufferMs int `json:"pbsBufferMs"` + AccountId string `json:"accountId"` + PlacementId string `json:"placementId"` + Host string `json:"pbsHost"` + PbsBufferMs int `json:"pbsBufferMs"` + UseSourceBidderCode bool `json:"useSourceBidderCode,omitempty"` } diff --git a/static/bidder-params/relevantdigital.json b/static/bidder-params/relevantdigital.json index 5f88d85fe5..a3c1ad027d 100644 --- a/static/bidder-params/relevantdigital.json +++ b/static/bidder-params/relevantdigital.json @@ -19,6 +19,10 @@ "pbsBufferMs": { "type": "number", "description": "TMax buffer, default is 250" + }, + "useSourceBidderCode": { + "type": "boolean", + "description": "Use the bidder code of the actual server-side bidder in bid responses" } }, "required": [ From f0a03396bd5189af815ed4f5b26f08076f64f475 Mon Sep 17 00:00:00 2001 From: bTimor <btimor.dev@gmail.com> Date: Tue, 2 Jun 2026 17:19:08 +0300 Subject: [PATCH 223/272] New Adapter: Scalibur (#4640) --- adapters/scalibur/params_test.go | 51 +++ adapters/scalibur/scalibur.go | 320 ++++++++++++++++ adapters/scalibur/scalibur_test.go | 344 ++++++++++++++++++ .../exemplary/bid-floor-eur-to-usd.json | 80 ++++ .../scaliburtest/exemplary/bid-floor-usd.json | 69 ++++ .../scaliburtest/exemplary/debug.json | 59 +++ .../scaliburtest/exemplary/debug_prebid.json | 62 ++++ .../scalibur/scaliburtest/exemplary/gpid.json | 65 ++++ .../scaliburtest/exemplary/mtype.json | 58 +++ .../scaliburtest/exemplary/mtype_video.json | 68 ++++ .../exemplary/success_banner.json | 61 ++++ .../scaliburtest/exemplary/video.json | 78 ++++ .../exemplary/video_vast_url.json | 67 ++++ .../bid-floor-currency-conversion-error.json | 34 ++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_scalibur.go | 11 + static/bidder-info/scalibur.yaml | 25 ++ static/bidder-params/scalibur.json | 22 ++ 19 files changed, 1478 insertions(+) create mode 100644 adapters/scalibur/params_test.go create mode 100644 adapters/scalibur/scalibur.go create mode 100644 adapters/scalibur/scalibur_test.go create mode 100644 adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/debug.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/debug_prebid.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/gpid.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/mtype.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/mtype_video.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/success_banner.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/video.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/video_vast_url.json create mode 100644 adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json create mode 100644 openrtb_ext/imp_scalibur.go create mode 100644 static/bidder-info/scalibur.yaml create mode 100644 static/bidder-params/scalibur.json diff --git a/adapters/scalibur/params_test.go b/adapters/scalibur/params_test.go new file mode 100644 index 0000000000..994a8fb23b --- /dev/null +++ b/adapters/scalibur/params_test.go @@ -0,0 +1,51 @@ +package scalibur + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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.BidderScalibur, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected scalibur 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.BidderScalibur, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId":"p123"}`, + `{"placementId":"p123", "bidfloor": 1.5}`, + `{"placementId":"p123", "bidfloor": 1.5, "bidfloorcur": "USD"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `[]`, + `{}`, + `{"placementId": 123}`, + `{"bidfloor": 1.5}`, +} diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go new file mode 100644 index 0000000000..f4c77ffa5b --- /dev/null +++ b/adapters/scalibur/scalibur.go @@ -0,0 +1,320 @@ +package scalibur + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "text/template" + + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint *template.Template +} + +// Builder builds a new instance of the Scalibur adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + temp, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + return &adapter{ + endpoint: temp, + }, nil +} + +// MakeRequests creates the HTTP requests which should be made to fetch bids from Scalibur. +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + var validImps []openrtb2.Imp + + // Process each impression + for _, imp := range request.Imp { + scaliburExt, err := parseScaliburExt(imp.Ext) + if err != nil { + errs = append(errs, err) + continue + } + + impCopy := imp + + // Apply bid floor and currency + if scaliburExt.BidFloor != nil && *scaliburExt.BidFloor > 0 { + impCopy.BidFloor = *scaliburExt.BidFloor + if scaliburExt.BidFloorCur != "" { + impCopy.BidFloorCur = scaliburExt.BidFloorCur + } + } + + if impCopy.BidFloor > 0 && impCopy.BidFloorCur != "" && impCopy.BidFloorCur != "USD" { + convertedValue, err := reqInfo.ConvertCurrency(impCopy.BidFloor, impCopy.BidFloorCur, "USD") + if err != nil { + errs = append(errs, err) + continue + } + impCopy.BidFloor = convertedValue + impCopy.BidFloorCur = "USD" + } + + if impCopy.BidFloorCur == "" { + impCopy.BidFloorCur = "USD" + } + + // Prepare imp.ext with placementId and params + impExtData := make(map[string]interface{}) + impExtData["placementId"] = scaliburExt.PlacementID + + if impCopy.BidFloor > 0 { + impExtData["bidfloor"] = impCopy.BidFloor + } + impExtData["bidfloorcur"] = impCopy.BidFloorCur + + // Preserve GPID if present + var rawExt map[string]json.RawMessage + if err := jsonutil.Unmarshal(imp.Ext, &rawExt); err == nil { + if gpid, ok := rawExt["gpid"]; ok { + impExtData["gpid"] = json.RawMessage(gpid) + } + } + + impExt, err := jsonutil.Marshal(impExtData) + if err != nil { + errs = append(errs, err) + continue + } + impCopy.Ext = impExt + + // Apply video defaults (matching JS defaults) + if impCopy.Video != nil { + videoCopy := *impCopy.Video + + // Note: In openrtb v20, field names are capitalized (MIMEs not Mimes) + if len(videoCopy.MIMEs) == 0 { + videoCopy.MIMEs = []string{"video/mp4"} + } + if videoCopy.MinDuration == 0 { + videoCopy.MinDuration = 1 + } + if videoCopy.MaxDuration == 0 { + videoCopy.MaxDuration = 180 + } + if videoCopy.MaxBitRate == 0 { + videoCopy.MaxBitRate = 30000 + } + if len(videoCopy.Protocols) == 0 { + // Use adcom1.MediaCreativeSubtype for protocols in v20 + videoCopy.Protocols = []adcom1.MediaCreativeSubtype{2, 3, 5, 6} + } + // Note: In openrtb v20, W and H are pointers + if videoCopy.W == nil || *videoCopy.W == 0 { + w := int64(640) + videoCopy.W = &w + } + if videoCopy.H == nil || *videoCopy.H == 0 { + h := int64(480) + videoCopy.H = &h + } + if videoCopy.Placement == 0 { + videoCopy.Placement = 1 + } + if videoCopy.Linearity == 0 { + videoCopy.Linearity = 1 + } + + impCopy.Video = &videoCopy + } + + validImps = append(validImps, impCopy) + } + + // If no valid impressions, return errors + if len(validImps) == 0 { + return nil, errs + } + + // Create the outgoing request + requestCopy := *request + requestCopy.Imp = validImps + requestCopy.Cur = nil + + isDebug := request.Test == 1 + if !isDebug && len(request.Ext) > 0 { + var extRequest openrtb_ext.ExtRequest + if err := jsonutil.Unmarshal(request.Ext, &extRequest); err == nil { + isDebug = extRequest.Prebid.Debug + } + } + + if isDebug { + reqExt := openrtb_ext.ExtRequestScalibur{IsDebug: 1} + if reqExtJSON, err := jsonutil.Marshal(reqExt); err == nil { + requestCopy.Ext = reqExtJSON + } + } else { + requestCopy.Ext = nil + } + + reqJSON, err := jsonutil.Marshal(requestCopy) + if err != nil { + return nil, append(errs, err) + } + + var endpointBuffer bytes.Buffer + if err := a.endpoint.Execute(&endpointBuffer, nil); err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: endpointBuffer.String(), + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), + } + + return []*adapters.RequestData{requestData}, errs +} + +// MakeBids unpacks the server's response into bids. +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{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + // Parse the external request to get impression details + var bidReq openrtb2.BidRequest + if err := jsonutil.Unmarshal(externalRequest.Body, &bidReq); err != nil { + return nil, []error{err} + } + + // Build impression map for lookup + impMap := make(map[string]*openrtb2.Imp, len(bidReq.Imp)) + for i := range bidReq.Imp { + impMap[bidReq.Imp[i].ID] = &bidReq.Imp[i] + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidReq.Imp)) + + // Set currency + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } else { + bidResponse.Currency = "USD" + } + + // Process each seat bid + for _, seatBid := range bidResp.SeatBid { + for _, bid := range seatBid.Bid { + // Find the corresponding imp + imp, found := impMap[bid.ImpID] + if !found { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Invalid bid imp ID %s", bid.ImpID), + }} + } + + // Determine bid type based on imp + bidType, err := getBidMediaType(bid, imp) + if err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: err.Error(), + }} + } + + bidCopy := bid + + // Handle video VAST + if bidType == openrtb_ext.BidTypeVideo { + // Try to extract custom fields vastXml and vastUrl from bid.ext + var bidExtData struct { + VastXML string `json:"vastXml"` + VastURL string `json:"vastUrl"` + } + if bid.Ext != nil { + if err := jsonutil.Unmarshal(bid.Ext, &bidExtData); err == nil { + if bidExtData.VastXML != "" { + bidCopy.AdM = bidExtData.VastXML + } else if bidExtData.VastURL != "" && bidCopy.AdM == "" { + // Wrap VAST URL in VAST wrapper + bidCopy.AdM = fmt.Sprintf(`<VAST version="3.0"><Ad><Wrapper><VASTAdTagURI><![CDATA[%s]]></VASTAdTagURI></Wrapper></Ad></VAST>`, bidExtData.VastURL) + } + } + } + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bidCopy, + BidType: bidType, + }) + } + } + + if len(bidResponse.Bids) == 0 { + return nil, nil + } + + return bidResponse, nil +} + +// parseScaliburExt extracts Scalibur-specific parameters from the impression extension. +func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(impExt, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to parse imp.ext: %s", err.Error()), + } + } + + var scaliburExt openrtb_ext.ExtImpScalibur + if err := jsonutil.Unmarshal(bidderExt.Bidder, &scaliburExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to parse Scalibur params: %s", err.Error()), + } + } + + return &scaliburExt, nil +} + +// getBidMediaType determines the media type based on the impression +func getBidMediaType(bid openrtb2.Bid, imp *openrtb2.Imp) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + } + + // Fallback for bidders not supporting mtype (non-multi-format requests) + if imp.Banner != nil && imp.Video == nil { + return openrtb_ext.BidTypeBanner, nil + } + if imp.Video != nil && imp.Banner == nil { + return openrtb_ext.BidTypeVideo, nil + } + + return "", fmt.Errorf("unsupported or ambiguous media type for bid id=%s", bid.ID) +} diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go new file mode 100644 index 0000000000..3199e8ef66 --- /dev/null +++ b/adapters/scalibur/scalibur_test.go @@ -0,0 +1,344 @@ +package scalibur + +import ( + "encoding/json" + "net/http" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newTestAdapter() adapters.Bidder { + adapter, _ := Builder( + openrtb_ext.BidderScalibur, + config.Adapter{Endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server"}, + config.Server{}, + ) + return adapter +} + +// +// ------------------------------------------------------------------------------------------ +// MAKE REQUESTS TESTS +// ------------------------------------------------------------------------------------------ +// + +func TestJsonSamples(t *testing.T) { + adapterstest.RunJSONBidderTest(t, "scaliburtest", newTestAdapter()) +} + +func TestMakeRequests_SuccessBanner(t *testing.T) { + bidder := newTestAdapter() + + ext, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{ + "placementId": "p123", + "bidfloor": 1.25, + "bidfloorcur": "EUR" + }`), + }) + + req := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Ext: ext, + Banner: &openrtb2.Banner{ + W: ptrInt64(300), H: ptrInt64(250), + }, + }, + }, + Site: &openrtb2.Site{Page: "https://test.com"}, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{ + CurrencyConversions: &mockConversions{}, + }) + + require.Len(t, errs, 0) + require.Len(t, requests, 1) + + r := requests[0] + assert.Equal(t, "https://srv.scalibur.io/adserver/ortb?type=prebid-server", r.Uri) + assert.Equal(t, "POST", r.Method) + assert.Contains(t, r.Headers.Get("Content-Type"), "application/json") + + // Ensure body contains rewritten ext fields + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(r.Body, &out)) + require.Len(t, out.Imp, 1) + + imp := out.Imp[0] + + assert.Equal(t, float64(1.25), imp.BidFloor) + assert.Equal(t, "USD", imp.BidFloorCur) + + var outExt map[string]interface{} + require.NoError(t, json.Unmarshal(imp.Ext, &outExt)) + assert.Equal(t, "p123", outExt["placementId"]) +} + +func TestMakeRequests_InvalidExt(t *testing.T) { + bidder := newTestAdapter() + + badExt, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{invalid`), + }) + + req := &openrtb2.BidRequest{ + ID: "req2", + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Ext: badExt, + Banner: &openrtb2.Banner{ + W: ptrInt64(300), H: ptrInt64(250), + }, + }, + }, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + + require.Len(t, requests, 0) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Failed to parse imp.ext") +} + +func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { + bidder := newTestAdapter() + + ext, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{"placementId": "p123"}`), + }) + + req := &openrtb2.BidRequest{ + ID: "req-video", + Imp: []openrtb2.Imp{ + { + ID: "v1", + Ext: ext, + Video: &openrtb2.Video{ + // Intentionally empty → should fill defaults + }, + }, + }, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{ + CurrencyConversions: &mockConversions{}, + }) + + require.Len(t, errs, 0) + require.Len(t, requests, 1) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(requests[0].Body, &out)) + + v := out.Imp[0].Video + require.NotNil(t, v) + + assert.NotEmpty(t, v.MIMEs) + assert.NotZero(t, v.MinDuration) + assert.NotZero(t, v.MaxDuration) + assert.NotZero(t, v.MaxBitRate) + assert.NotEmpty(t, v.Protocols) + assert.NotNil(t, v.W) + assert.NotNil(t, v.H) + assert.NotZero(t, v.Placement) + assert.NotZero(t, v.Linearity) +} + +type mockConversions struct{} + +func (m *mockConversions) GetRate(from string, to string) (float64, error) { + return 1.0, nil +} + +func (m *mockConversions) GetRates() *map[string]map[string]float64 { + return nil +} + +// +// ------------------------------------------------------------------------------------------ +// MAKE BIDS TESTS +// ------------------------------------------------------------------------------------------ +// + +func TestMakeBids_SuccessBanner(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + { + ID: "1", + Banner: &openrtb2.Banner{W: ptrInt64(300), H: ptrInt64(250)}, + }, + }, + } + + mockReqData := &adapters.RequestData{ + Body: func() []byte { + b, _ := json.Marshal(mockReq) + return b + }(), + } + + mockResp := &openrtb2.BidResponse{ + ID: "resp1", + Cur: "USD", + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "b1", + ImpID: "1", + Price: 2.5, + AdM: "<div>ad markup</div>", + W: 300, + H: 250, + }, + }, + }, + }, + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: func() []byte { + b, _ := json.Marshal(mockResp) + return b + }(), + } + + bidderResp, errs := bidder.MakeBids(mockReq, mockReqData, respData) + + require.Len(t, errs, 0) + require.NotNil(t, bidderResp) + require.Len(t, bidderResp.Bids, 1) + + b := bidderResp.Bids[0] + assert.Equal(t, openrtb_ext.BidTypeBanner, b.BidType) + assert.Equal(t, float64(2.5), b.Bid.Price) + assert.Equal(t, "<div>ad markup</div>", b.Bid.AdM) +} + +func TestMakeBids_EmptySeatBid(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req2", + Imp: []openrtb2.Imp{}, + } + + mockReqData := &adapters.RequestData{ + Body: []byte(`{"id":"req2","imp":[]}`), + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id":"resp","seatbid":[]}`), + } + + bidderResp, errs := bidder.MakeBids(mockReq, mockReqData, respData) + + require.Len(t, errs, 0) + assert.Nil(t, bidderResp) +} + +func TestMakeBids_Status204(t *testing.T) { + bidder := newTestAdapter() + + respData := &adapters.ResponseData{ + StatusCode: http.StatusNoContent, + } + + resp, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, respData) + + assert.Nil(t, resp) + assert.Nil(t, errs) +} + +func TestMakeBids_InvalidJSON(t *testing.T) { + bidder := newTestAdapter() + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`not-json`), + } + + _, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, respData) + require.Len(t, errs, 1) +} + +func TestMakeBids_ImpNotFound(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + {ID: "1"}, + }, + } + + mockReqData := &adapters.RequestData{ + Body: []byte(`{"id":"req1","imp":[{"id":"1"}]}`), + } + + mockResp := &openrtb2.BidResponse{ + ID: "resp1", + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "b1", + ImpID: "non-existent", + }, + }, + }, + }, + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: func() []byte { + b, _ := json.Marshal(mockResp) + return b + }(), + } + + _, errs := bidder.MakeBids(mockReq, mockReqData, respData) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Invalid bid imp ID non-existent") +} + +func TestGetBidMediaType_Error(t *testing.T) { + bid := openrtb2.Bid{ + ID: "bid1", + ImpID: "imp1", + } + imp := &openrtb2.Imp{ + ID: "imp1", + // No banner or video + } + + _, err := getBidMediaType(bid, imp) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unsupported or ambiguous media type") +} + +func TestParseScaliburExt_ErrorCases(t *testing.T) { + _, err := parseScaliburExt(json.RawMessage(`{invalid`)) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed to parse imp.ext") +} + +func ptrInt64(x int64) *int64 { return &x } diff --git a/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json b/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json new file mode 100644 index 0000000000..c9d3b37c39 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.0, + "bidfloorcur": "EUR" + } + } + }], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2 + } + } + } + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloor": 1.2, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloor": 1.2, + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.2, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.2, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json b/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json new file mode 100644 index 0000000000..2549a4d7e0 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "USD" + } + } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloor": 1.5, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/exemplary/debug.json b/adapters/scalibur/scaliburtest/exemplary/debug.json new file mode 100644 index 0000000000..4422ffb07e --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/debug.json @@ -0,0 +1,59 @@ +{ + "mockBidRequest": { + "id": "test-debug-request", + "test": 1, + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-debug-request", + "test": 1, + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }], + "ext": { "isDebug": 1 } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-debug-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id" + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id" + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json b/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json new file mode 100644 index 0000000000..5f780c6810 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-debug-prebid-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }], + "ext": { + "prebid": { + "debug": true + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-debug-prebid-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }], + "ext": { "isDebug": 1 } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-debug-prebid-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id" + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id" + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/gpid.json b/adapters/scalibur/scaliburtest/exemplary/gpid.json new file mode 100644 index 0000000000..393c8a86dd --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/gpid.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { "placementId": "test-scl-placement" }, + "gpid": "test-gpid-value" + } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloorcur": "USD", + "gpid": "test-gpid-value" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/mtype.json b/adapters/scalibur/scaliburtest/exemplary/mtype.json new file mode 100644 index 0000000000..4256373d8f --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/mtype.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-mtype-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-mtype-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-mtype-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "mtype": 1 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/mtype_video.json b/adapters/scalibur/scaliburtest/exemplary/mtype_video.json new file mode 100644 index 0000000000..32121a1a08 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/mtype_video.json @@ -0,0 +1,68 @@ +{ + "mockBidRequest": { + "id": "test-mtype-video-request", + "imp": [{ + "id": "test-imp-id", + "video": { "mimes": ["video/mp4"] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-mtype-video-request", + "imp": [{ + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "maxbitrate": 30000, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-mtype-video-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<VAST>...</VAST>", + "crid": "test-creative-id", + "mtype": 2 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<VAST>...</VAST>", + "crid": "test-creative-id", + "mtype": 2 + }, + "type": "video" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/success_banner.json b/adapters/scalibur/scaliburtest/exemplary/success_banner.json new file mode 100644 index 0000000000..aabe2beb47 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/success_banner.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-scl-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "<html>...</html>", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/exemplary/video.json b/adapters/scalibur/scaliburtest/exemplary/video.json new file mode 100644 index 0000000000..7eaea7a289 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/video.json @@ -0,0 +1,78 @@ +{ + "mockBidRequest": { + "id": "test-video-req", + "imp": [{ + "id": "video-imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": "46" + } + } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["video-imp-1"], + "body": { + "id": "test-video-req", + "imp": [{ + "id": "video-imp-1", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1, + "maxbitrate": 30000 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "46", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-req", + "seatbid": [{ + "bid": [{ + "id": "bid-v1", + "impid": "video-imp-1", + "price": 1.5, + "crid": "cr-video", + "ext": { + "vastXml": "<VAST>...</VAST>" + } + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "bid-v1", + "impid": "video-imp-1", + "price": 1.5, + "adm": "<VAST>...</VAST>", + "crid": "cr-video", + "ext": { "vastXml": "<VAST>...</VAST>" } + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/exemplary/video_vast_url.json b/adapters/scalibur/scaliburtest/exemplary/video_vast_url.json new file mode 100644 index 0000000000..f00833b95b --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/video_vast_url.json @@ -0,0 +1,67 @@ +{ + "mockBidRequest": { + "id": "test-video-url-req", + "imp": [{ + "id": "video-imp-2", + "video": { "mimes": ["video/mp4"] }, + "ext": { "bidder": { "placementId": "46" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["video-imp-2"], + "body": { + "id": "test-video-url-req", + "imp": [{ + "id": "video-imp-2", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1, + "maxbitrate": 30000 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "46", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-url-req", + "seatbid": [{ + "bid": [{ + "id": "bid-v2", + "impid": "video-imp-2", + "price": 2.0, + "ext": { + "vastUrl": "https://cdn.scalibur.io/vast.xml" + } + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "bid-v2", + "impid": "video-imp-2", + "price": 2.0, + "adm": "<VAST version=\"3.0\"><Ad><Wrapper><VASTAdTagURI><![CDATA[https://cdn.scalibur.io/vast.xml]]></VASTAdTagURI></Wrapper></Ad></VAST>", + "ext": { "vastUrl": "https://cdn.scalibur.io/vast.xml" } + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json b/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json new file mode 100644 index 0000000000..a154313934 --- /dev/null +++ b/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json @@ -0,0 +1,34 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "EUR" + } + } + }], + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 1.3 + } + } + } + } + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Currency conversion rate not found: 'EUR' => 'USD'", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 6a3d9b539e..2d6526a190 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -202,6 +202,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/rtbstack" "github.com/prebid/prebid-server/v4/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v4/adapters/sa_lunamedia" + "github.com/prebid/prebid-server/v4/adapters/scalibur" "github.com/prebid/prebid-server/v4/adapters/seedingAlliance" "github.com/prebid/prebid-server/v4/adapters/seedtag" "github.com/prebid/prebid-server/v4/adapters/sharethrough" @@ -476,6 +477,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSeedingAlliance: seedingAlliance.Builder, openrtb_ext.BidderSeedtag: seedtag.Builder, openrtb_ext.BidderSaLunaMedia: salunamedia.Builder, + openrtb_ext.BidderScalibur: scalibur.Builder, openrtb_ext.BidderSharethrough: sharethrough.Builder, openrtb_ext.BidderShowheroes: showheroes.Builder, openrtb_ext.BidderSilverMob: silvermob.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 97989ee54a..9e9cfaa761 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -222,6 +222,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSeedingAlliance, BidderSeedtag, BidderSaLunaMedia, + BidderScalibur, BidderSharethrough, BidderShowheroes, BidderSilverMob, @@ -598,6 +599,7 @@ const ( BidderSeedingAlliance BidderName = "seedingAlliance" BidderSeedtag BidderName = "seedtag" BidderSaLunaMedia BidderName = "sa_lunamedia" + BidderScalibur BidderName = "scalibur" BidderSharethrough BidderName = "sharethrough" BidderShowheroes BidderName = "showheroes" BidderSilverMob BidderName = "silvermob" diff --git a/openrtb_ext/imp_scalibur.go b/openrtb_ext/imp_scalibur.go new file mode 100644 index 0000000000..9a0ff7902f --- /dev/null +++ b/openrtb_ext/imp_scalibur.go @@ -0,0 +1,11 @@ +package openrtb_ext + +type ExtImpScalibur struct { + PlacementID string `json:"placementId"` // required + BidFloor *float64 `json:"bidfloor,omitempty"` // optional, used as fallback + BidFloorCur string `json:"bidfloorcur,omitempty"` // optional, defaults to USD if empty +} + +type ExtRequestScalibur struct { + IsDebug int `json:"isDebug,omitempty"` +} diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml new file mode 100644 index 0000000000..8b82f56a3f --- /dev/null +++ b/static/bidder-info/scalibur.yaml @@ -0,0 +1,25 @@ +endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server" +# Leave disabled: false → adapter enabled +compression: gzip +disabled: false +maintainer: + email: "support@scalibur.io" +gvlVendorID: 1471 +openrtb: + version: 2.6 + gpp-supported: true +capabilities: + site: + mediaTypes: + - banner + - video + app: + mediaTypes: + - banner + - video +userSync: + iframe: + url: "https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "[PBS_UID]" + supports: + - iframe \ No newline at end of file diff --git a/static/bidder-params/scalibur.json b/static/bidder-params/scalibur.json new file mode 100644 index 0000000000..05a12e99f2 --- /dev/null +++ b/static/bidder-params/scalibur.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Scalibur Adapter Params", + "description": "A valid BidderParams object for the Scalibur adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1 + }, + "bidfloor": { + "type": "number", + "minimum": 0 + }, + "bidfloorcur": { + "type": "string" + } + }, + "required": [ + "placementId" + ] +} From 494ac271cd4b5024df9123ef25ca3cff96390be3 Mon Sep 17 00:00:00 2001 From: Patrick McCann <patmmccann@gmail.com> Date: Fri, 5 Jun 2026 17:15:08 -0400 Subject: [PATCH 224/272] Validate host & subdomain bidder params (#4802) Co-authored-by: bsardo <1168933+bsardo@users.noreply.github.com> --- adapters/acuityads/acuityads.go | 4 + .../supplemental/invalid-host.json | 30 ++++ adapters/acuityads/params_test.go | 16 +- adapters/adhese/adhese.go | 5 + .../supplemental/invalid-account.json | 26 ++++ adapters/adhese/params_test.go | 15 ++ adapters/bidmachine/bidmachine.go | 4 + .../supplemental/invalid-host.json | 32 ++++ adapters/bidmachine/params_test.go | 51 +++---- adapters/kayzen/kayzen.go | 4 + .../kayzentest/supplemental/invalid-zone.json | 28 ++++ adapters/kayzen/params_test.go | 15 ++ adapters/rediads/params_test.go | 20 ++- adapters/rediads/rediads.go | 4 + .../supplemental/invalid-endpoint.json | 31 ++++ adapters/relevantdigital/params_test.go | 30 +++- adapters/relevantdigital/relevantdigital.go | 4 + .../supplemental/host-normalization.json | 137 ++++++++++++++++++ .../supplemental/invalid-host.json | 31 ++++ adapters/smartyads/params_test.go | 21 ++- adapters/smartyads/smartyads.go | 4 + .../supplemental/invalid-host.json | 31 ++++ adapters/tappx/params_test.go | 16 +- adapters/tappx/tappx.go | 15 +- adapters/tradplus/params_test.go | 18 ++- adapters/tradplus/tradplus.go | 4 + .../supplemental/invalid-zoneid.json | 25 ++++ adapters/trafficgate/params_test.go | 16 +- adapters/trafficgate/trafficgate.go | 4 + .../supplemental/invalid-host.json | 35 +++++ adapters/zeroclickfraud/params_test.go | 65 +++++++++ adapters/zeroclickfraud/zeroclickfraud.go | 3 +- .../supplemental/invalid-host.json | 31 ++++ static/bidder-params/acuityads.json | 10 +- static/bidder-params/adhese.json | 1 + static/bidder-params/bidmachine.json | 51 +++---- static/bidder-params/kayzen.json | 1 + static/bidder-params/rediads.json | 3 +- static/bidder-params/relevantdigital.json | 61 ++++---- static/bidder-params/smartyads.json | 11 +- static/bidder-params/tappx.json | 86 +++++------ static/bidder-params/tradplus.json | 3 +- static/bidder-params/trafficgate.json | 8 +- static/bidder-params/zeroclickfraud.json | 25 ++-- util/urlutil/security.go | 12 ++ util/urlutil/security_test.go | 68 +++++++++ 46 files changed, 950 insertions(+), 165 deletions(-) create mode 100644 adapters/acuityads/acuityadstest/supplemental/invalid-host.json create mode 100644 adapters/adhese/adhesetest/supplemental/invalid-account.json create mode 100644 adapters/bidmachine/bidmachinetest/supplemental/invalid-host.json create mode 100644 adapters/kayzen/kayzentest/supplemental/invalid-zone.json create mode 100644 adapters/rediads/rediadstest/supplemental/invalid-endpoint.json create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/host-normalization.json create mode 100644 adapters/relevantdigital/relevantdigitaltest/supplemental/invalid-host.json create mode 100644 adapters/smartyads/smartyadstest/supplemental/invalid-host.json create mode 100644 adapters/tradplus/tradplustest/supplemental/invalid-zoneid.json create mode 100644 adapters/trafficgate/trafficgatetest/supplemental/invalid-host.json create mode 100644 adapters/zeroclickfraud/params_test.go create mode 100644 adapters/zeroclickfraud/zeroclickfraudtest/supplemental/invalid-host.json create mode 100644 util/urlutil/security.go create mode 100644 util/urlutil/security_test.go diff --git a/adapters/acuityads/acuityads.go b/adapters/acuityads/acuityads.go index f9ae431b0b..4c945d236d 100644 --- a/adapters/acuityads/acuityads.go +++ b/adapters/acuityads/acuityads.go @@ -13,6 +13,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type AcuityAdsAdapter struct { @@ -107,6 +108,9 @@ func (a *AcuityAdsAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.Ext } func (a *AcuityAdsAdapter) buildEndpointURL(params *openrtb_ext.ExtAcuityAds) (string, error) { + if !urlutil.IsSafeHost(params.Host) { + return "", &errortypes.BadInput{Message: "Invalid Host"} + } endpointParams := macros.EndpointTemplateParams{Host: params.Host, AccountID: params.AccountID} return macros.ResolveMacros(a.endpoint, endpointParams) } diff --git a/adapters/acuityads/acuityadstest/supplemental/invalid-host.json b/adapters/acuityads/acuityadstest/supplemental/invalid-host.json new file mode 100644 index 0000000000..c74bf89dc1 --- /dev/null +++ b/adapters/acuityads/acuityadstest/supplemental/invalid-host.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "host": "evil.com/path?redirect=http://attacker.com#", + "accountid": "testaccount" + } + } + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid Host", + "comparison": "literal" + } + ] +} diff --git a/adapters/acuityads/params_test.go b/adapters/acuityads/params_test.go index a1fe43f13b..cdd746eff6 100644 --- a/adapters/acuityads/params_test.go +++ b/adapters/acuityads/params_test.go @@ -8,7 +8,12 @@ import ( ) var validParams = []string{ - `{ "host": "ep1", "accountid": "hash" }`, + `{ "host": "host", "accountid": "hash" }`, + `{ "host": "host.example.com", "accountid": "hash" }`, + `{ "host": "host.example.com:8080", "accountid": "hash" }`, + `{ "host": "host-example.test", "accountid": "hash" }`, + `{ "host": "Host.Example.com", "accountid": "hash" }`, + `{ "host": "localhost:3000", "accountid": "hash" }`, } func TestValidParams(t *testing.T) { @@ -35,6 +40,15 @@ var invalidParams = []string{ `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, `{ "accountid": "hash" }`, `{ "host": "", "accountid": "" }`, + `{ "host": "/path", "accountid": "hash" }`, + `{ "host": "//evil.com", "accountid": "hash" }`, + `{ "host": "host/path", "accountid": "hash" }`, + `{ "host": "host?query=1", "accountid": "hash" }`, + `{ "host": "host#fragment", "accountid": "hash" }`, + `{ "host": "user@host", "accountid": "hash" }`, + `{ "host": "https://host.com", "accountid": "hash" }`, + `{ "host": "host:notaport", "accountid": "hash" }`, + `{ "host": "host:8080:extra", "accountid": "hash" }`, } func TestInvalidParams(t *testing.T) { diff --git a/adapters/adhese/adhese.go b/adapters/adhese/adhese.go index 79bfaef404..27dd0140b8 100644 --- a/adapters/adhese/adhese.go +++ b/adapters/adhese/adhese.go @@ -11,6 +11,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -66,6 +67,10 @@ func (a *adapter) MakeRequests( modifiedRequest := *request modifiedRequest.Imp[0].Ext = modifiedExt + if !urlutil.IsSafeHost(params.Account) { + return nil, []error{&errortypes.BadInput{Message: "Invalid account"}} + } + // create a map of macros to resolve endpointParams := macros.EndpointTemplateParams{AccountID: params.Account} diff --git a/adapters/adhese/adhesetest/supplemental/invalid-account.json b/adapters/adhese/adhesetest/supplemental/invalid-account.json new file mode 100644 index 0000000000..f833bf8965 --- /dev/null +++ b/adapters/adhese/adhesetest/supplemental/invalid-account.json @@ -0,0 +1,26 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "account": "evil.com/path?redirect=http://attacker.com#", + "location": "loc1", + "format": "for1" + } + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid account", + "comparison": "literal" + } + ] +} diff --git a/adapters/adhese/params_test.go b/adapters/adhese/params_test.go index ec0f2c5421..5b9ce9e237 100644 --- a/adapters/adhese/params_test.go +++ b/adapters/adhese/params_test.go @@ -38,6 +38,11 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"account": "demo", "location": "loc1", "format": "for1"}`, `{"account": "demo", "location": "loc1", "format": "for1", "targets": { "ab": ["test", "test2"]}}`, + `{"account": "host", "location": "loc1", "format": "for1"}`, + `{"account": "host.example.com", "location": "loc1", "format": "for1"}`, + `{"account": "host-example.test", "location": "loc1", "format": "for1"}`, + `{"account": "Host.Example.com", "location": "loc1", "format": "for1"}`, + `{"account": "localhost", "location": "loc1", "format": "for1"}`, } var invalidParams = []string{ @@ -55,4 +60,14 @@ var invalidParams = []string{ `{"account": "demo", "location": "loc1", "format": 5}`, `{"account": "demo", "location": "loc1", "format": "for1", "targets": "test"}`, `{"account": "demo", "location": "loc1", "format": "for1", "targets": 5}`, + `{"account": "/path", "location": "loc1", "format": "for1"}`, + `{"account": "//evil.com", "location": "loc1", "format": "for1"}`, + `{"account": "host/path", "location": "loc1", "format": "for1"}`, + `{"account": "host?query=1", "location": "loc1", "format": "for1"}`, + `{"account": "host#fragment", "location": "loc1", "format": "for1"}`, + `{"account": "user@host", "location": "loc1", "format": "for1"}`, + `{"account": "https://host.com", "location": "loc1", "format": "for1"}`, + `{"account": "host:notaport", "location": "loc1", "format": "for1"}`, + `{"account": "host:8080:extra", "location": "loc1", "format": "for1"}`, + `{"account": "host:8080", "location": "loc1", "format": "for1"}`, } diff --git a/adapters/bidmachine/bidmachine.go b/adapters/bidmachine/bidmachine.go index b56fff83dc..47fd8b90f1 100644 --- a/adapters/bidmachine/bidmachine.go +++ b/adapters/bidmachine/bidmachine.go @@ -18,6 +18,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -184,6 +185,9 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co const UndefinedMediaType = openrtb_ext.BidType("") func (a *adapter) buildEndpointURL(params openrtb_ext.ExtImpBidmachine) (string, error) { + if !urlutil.IsSafeHost(params.Host) { + return "", &errortypes.BadInput{Message: "Failed to create final URL with provided host"} + } endpointParams := macros.EndpointTemplateParams{Host: params.Host} uriString, errMacros := macros.ResolveMacros(a.endpoint, endpointParams) if errMacros != nil { diff --git a/adapters/bidmachine/bidmachinetest/supplemental/invalid-host.json b/adapters/bidmachine/bidmachinetest/supplemental/invalid-host.json new file mode 100644 index 0000000000..3182d6bf4a --- /dev/null +++ b/adapters/bidmachine/bidmachinetest/supplemental/invalid-host.json @@ -0,0 +1,32 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-impression-id-1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "host": "evil.com/path?redirect=http://attacker.com#", + "path": "auction/rtb/v2", + "seller_id": "1" + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Failed to create final URL with provided host", + "comparison": "literal" + } + ] +} diff --git a/adapters/bidmachine/params_test.go b/adapters/bidmachine/params_test.go index 56d796c27c..1f51f92a75 100644 --- a/adapters/bidmachine/params_test.go +++ b/adapters/bidmachine/params_test.go @@ -34,8 +34,12 @@ func TestInvalidParams(t *testing.T) { } var validParams = []string{ - `{"seller_id":"1", "host":"api-eu", "path":"auction/rtb/v2"}`, - `{"seller_id":"1", "host":"api-us", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host.example.com", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host.example.com:8080", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host-example.test", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"Host.Example.com", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"localhost:3000", "path":"auction/rtb/v2"}`, } var invalidParams = []string{ @@ -47,32 +51,19 @@ var invalidParams = []string{ `[]`, `{}`, `{"some_random_field":""}`, - `{"seller_id":""}`, - `{"seller_id": 1}`, - `{"seller_id": 1.2}`, - `{"seller_id": null}`, - `{"seller_id": true}`, - `{"seller_id": []}`, - `{"seller_id": {}}`, - `{"host":""}`, - `{"host": 1}`, - `{"host": 1.2}`, - `{"host": null}`, - `{"host": true}`, - `{"host": []}`, - `{"host": {}}`, - `{"path":""}`, - `{"path": 1}`, - `{"path": 1.2}`, - `{"path": null}`, - `{"path": true}`, - `{"path": []}`, - `{"path": {}}`, - `{"seller_id":"", "path": "", host: ""}`, - `{"seller_id": 1, "path": 2, host: 3}`, - `{"seller_id": 1.2}, "path": 5.5, host: 3.3`, - `{"seller_id": null, "path": null, host: null}`, - `{"seller_id": true, "path": false, host: true}`, - `{"seller_id": [], "path": [], host: []}`, - `{"seller_id": {}, "path": {}, host: {}}`, + `{"seller_id":"", "host":"host", "path":"auction/rtb/v2"}`, + `{"host":"host", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host", "path":""}`, + `{"seller_id":"1", "host":"host"}`, + `{"seller_id":"1", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"/path", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"//evil.com", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host/path", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host?query=1", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host#fragment", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"user@host", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"https://host.com", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host:notaport", "path":"auction/rtb/v2"}`, + `{"seller_id":"1", "host":"host:8080:extra", "path":"auction/rtb/v2"}`, } diff --git a/adapters/kayzen/kayzen.go b/adapters/kayzen/kayzen.go index 9c866918a9..d5835a38e6 100644 --- a/adapters/kayzen/kayzen.go +++ b/adapters/kayzen/kayzen.go @@ -13,6 +13,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -92,6 +93,9 @@ func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtKayzen, e } func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtKayzen) (string, error) { + if !urlutil.IsSafeHost(params.Zone) { + return "", &errortypes.BadInput{Message: "Invalid Zone"} + } endpointParams := macros.EndpointTemplateParams{ ZoneID: params.Zone, AccountID: params.Exchange, diff --git a/adapters/kayzen/kayzentest/supplemental/invalid-zone.json b/adapters/kayzen/kayzentest/supplemental/invalid-zone.json new file mode 100644 index 0000000000..fb22602ffa --- /dev/null +++ b/adapters/kayzen/kayzentest/supplemental/invalid-zone.json @@ -0,0 +1,28 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 50}] + }, + "ext": { + "bidder": { + "zone": "evil.com/path?redirect=http://attacker.com#", + "exchange": "ex" + } + } + } + ], + "site": { + "page": "test.com" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid Zone", + "comparison": "literal" + } + ] +} diff --git a/adapters/kayzen/params_test.go b/adapters/kayzen/params_test.go index 66666e1980..45f07b9eed 100644 --- a/adapters/kayzen/params_test.go +++ b/adapters/kayzen/params_test.go @@ -9,6 +9,11 @@ import ( var validParams = []string{ `{ "zone": "dc", "exchange": "ex" }`, + `{ "zone": "host", "exchange": "ex" }`, + `{ "zone": "host.example.com", "exchange": "ex" }`, + `{ "zone": "host-example.test", "exchange": "ex" }`, + `{ "zone": "Host.Example.com", "exchange": "ex" }`, + `{ "zone": "localhost", "exchange": "ex" }`, } func TestValidParams(t *testing.T) { @@ -39,6 +44,16 @@ var invalidParams = []string{ `{ "exchange": "", "zone" : "" }`, `{ "exchange": "ex", "zone" : "" }`, `{ "exchange": "", "zone" : "dc" }`, + `{ "zone": "/path", "exchange": "ex" }`, + `{ "zone": "//evil.com", "exchange": "ex" }`, + `{ "zone": "host/path", "exchange": "ex" }`, + `{ "zone": "host?query=1", "exchange": "ex" }`, + `{ "zone": "host#fragment", "exchange": "ex" }`, + `{ "zone": "user@host", "exchange": "ex" }`, + `{ "zone": "https://host.com", "exchange": "ex" }`, + `{ "zone": "host:notaport", "exchange": "ex" }`, + `{ "zone": "host:8080:extra", "exchange": "ex" }`, + `{ "zone": "host:8080", "exchange": "ex" }`, } func TestInvalidParams(t *testing.T) { diff --git a/adapters/rediads/params_test.go b/adapters/rediads/params_test.go index d191206823..13ba386eff 100644 --- a/adapters/rediads/params_test.go +++ b/adapters/rediads/params_test.go @@ -36,9 +36,25 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"account_id": "123"}`, `{"account_id": "123", "slot": "12345"}`, - `{"account_id": "123", "slot": "12345", "endpoint": "https://bidding.rediads.com/openrtb2/auction"}`, + `{"account_id": "123", "slot": "12345", "endpoint": "bidding2"}`, + `{"account_id": "123", "endpoint": "host"}`, + `{"account_id": "123", "endpoint": "host.example.com"}`, + `{"account_id": "123", "endpoint": "host-example.test"}`, + `{"account_id": "123", "endpoint": "Host.Example.com"}`, + `{"account_id": "123", "endpoint": "localhost"}`, } var invalidParams = []string{ - `{"account": 42}`, `{}`, + `{"account": 42}`, + `{}`, + `{"account_id": "123", "endpoint": "/path"}`, + `{"account_id": "123", "endpoint": "//evil.com"}`, + `{"account_id": "123", "endpoint": "host/path"}`, + `{"account_id": "123", "endpoint": "host?query=1"}`, + `{"account_id": "123", "endpoint": "host#fragment"}`, + `{"account_id": "123", "endpoint": "user@host"}`, + `{"account_id": "123", "endpoint": "https://host.com"}`, + `{"account_id": "123", "endpoint": "host:notaport"}`, + `{"account_id": "123", "endpoint": "host:8080:extra"}`, + `{"account_id": "123", "endpoint": "host:8080"}`, } diff --git a/adapters/rediads/rediads.go b/adapters/rediads/rediads.go index 349504219b..bbf6a8e1dc 100644 --- a/adapters/rediads/rediads.go +++ b/adapters/rediads/rediads.go @@ -12,6 +12,7 @@ import ( "github.com/prebid/prebid-server/v4/errortypes" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -99,6 +100,9 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte finalEndpoint := a.endpoint if endpoint != "" { + if !urlutil.IsSafeHost(endpoint) { + return nil, []error{&errortypes.BadInput{Message: "Invalid endpoint"}} + } parsedURL, _ := url.Parse(finalEndpoint) host := parsedURL.Host parts := strings.Split(host, ".") diff --git a/adapters/rediads/rediadstest/supplemental/invalid-endpoint.json b/adapters/rediads/rediadstest/supplemental/invalid-endpoint.json new file mode 100644 index 0000000000..5766b970d1 --- /dev/null +++ b/adapters/rediads/rediadstest/supplemental/invalid-endpoint.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "account_id": "123", + "endpoint": "evil.com/path?redirect=http://attacker.com#" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "pub1" + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid endpoint", + "comparison": "literal" + } + ] +} diff --git a/adapters/relevantdigital/params_test.go b/adapters/relevantdigital/params_test.go index 8505e4c478..21aad12ff1 100644 --- a/adapters/relevantdigital/params_test.go +++ b/adapters/relevantdigital/params_test.go @@ -34,12 +34,32 @@ func TestInvalidParams(t *testing.T) { } var validParams = []string{ - `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host" }`, - `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": true }`, - `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": false }`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host.example.com"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host.example.com:8080"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host-example.test"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "Host.Example.com"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "localhost:3000"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "https://foo.relevant-digital.com"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "http://foo.relevant-digital.com"}`, } var invalidParams = []string{ - `{"accountId": 123, "placementId" : 123, "pbsHost" : ""}`, - `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId" : "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost" : "some-host", "useSourceBidderCode": "somethingInvalid" }`, + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"accountId": 123, "placementId": 123, "pbsHost": ""}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host", "useSourceBidderCode": "somethingInvalid"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "/path"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "//evil.com"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host/path"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host?query=1"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host#fragment"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "user@host"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host:notaport"}`, + `{"accountId": "5fcf49f83a64ba6602b5be7e", "placementId": "63b68275b4f35962c8eec9b1_5fcf49f83a64ba6602b5be9a", "pbsHost": "host:8080:extra"}`, } diff --git a/adapters/relevantdigital/relevantdigital.go b/adapters/relevantdigital/relevantdigital.go index 44f1ebdf3f..9fa8174fea 100644 --- a/adapters/relevantdigital/relevantdigital.go +++ b/adapters/relevantdigital/relevantdigital.go @@ -16,6 +16,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" jsonpatch "gopkg.in/evanphx/json-patch.v5" ) @@ -182,6 +183,9 @@ func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtRelevantDigital) (stri params.Host = strings.ReplaceAll(params.Host, "http://", "") params.Host = strings.ReplaceAll(params.Host, "https://", "") params.Host = strings.ReplaceAll(params.Host, relevant_domain, "") + if !urlutil.IsSafeHost(params.Host) { + return "", &errortypes.BadInput{Message: "Invalid Host"} + } endpointParams := macros.EndpointTemplateParams{Host: params.Host} return macros.ResolveMacros(a.endpoint, endpointParams) diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/host-normalization.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/host-normalization.json new file mode 100644 index 0000000000..2f320358e2 --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/host-normalization.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "accountId": "620523ae7f4bbe1691bbb815", + "pbsHost": "https://fakeHost.relevant-digital.com", + "placementId": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com", + "publisher": { + "id": "1001", + "domain": "somepub.com" + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fakeHost.relevant-digital.com/openrtb2/auction", + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "imp": [ + { + "id": "div-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "620525862d7518bfd4bbb81e_620523b5d1dbed6b0fbbb817" + } + } + } + } + ], + "site": { + "domain": "somedomain.com", + "page": "https://somedomain.com", + "publisher": { + "id": "1001", + "domain": "somepub.com" + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "ext": { + "prebid": { + "debug": false, + "storedrequest": { + "id": "620523ae7f4bbe1691bbb815" + } + }, + "relevant": { + "adapterType": "server", + "count": 1 + } + }, + "tmax": 750 + }, + "impIDs": ["div-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "3621f78b-abdf-4562-8eca-1c5e893387d0", + "seatbid": [ + { + "seat": "relevantdigital", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-ad-markup", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "div-1", + "price": 0.5, + "adm": "some-ad-markup", + "crid": "crid_10", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/relevantdigital/relevantdigitaltest/supplemental/invalid-host.json b/adapters/relevantdigital/relevantdigitaltest/supplemental/invalid-host.json new file mode 100644 index 0000000000..1a29f98435 --- /dev/null +++ b/adapters/relevantdigital/relevantdigitaltest/supplemental/invalid-host.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "accountId": "testaccount", + "placementId": "testplacement", + "pbsHost": "evil.com/path?redirect=http://attacker.com#" + } + } + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid Host", + "comparison": "literal" + } + ] +} diff --git a/adapters/smartyads/params_test.go b/adapters/smartyads/params_test.go index f379c68f36..f33095cc51 100644 --- a/adapters/smartyads/params_test.go +++ b/adapters/smartyads/params_test.go @@ -8,7 +8,12 @@ import ( ) var validParams = []string{ - `{ "host": "ep1", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host.example.com", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host.example.com:8080", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host-example.test", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "Host.Example.com", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "localhost:3000", "sourceid": "partner", "accountid": "hash" }`, } func TestValidParams(t *testing.T) { @@ -34,8 +39,18 @@ var invalidParams = []string{ `{}`, `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, `{ "host": "ep1", "sourceid": "partner" }`, - `{ "host": "ep1, "accountid": "hash" }`, - `{ "sourceid": "partner", "sourceid": "partner" }`, + `{ "host": "ep1", "accountid": "hash" }`, + `{ "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "", "sourceid": "", "accountid": "" }`, + `{ "host": "/path", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "//evil.com", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host/path", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host?query=1", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host#fragment", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "user@host", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "https://host.com", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host:notaport", "sourceid": "partner", "accountid": "hash" }`, + `{ "host": "host:8080:extra", "sourceid": "partner", "accountid": "hash" }`, } func TestInvalidParams(t *testing.T) { diff --git a/adapters/smartyads/smartyads.go b/adapters/smartyads/smartyads.go index 9970b3af73..5be15f1158 100644 --- a/adapters/smartyads/smartyads.go +++ b/adapters/smartyads/smartyads.go @@ -14,6 +14,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type SmartyAdsAdapter struct { @@ -125,6 +126,9 @@ func (a *SmartyAdsAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.Ext } func (a *SmartyAdsAdapter) buildEndpointURL(params *openrtb_ext.ExtSmartyAds) (string, error) { + if !urlutil.IsSafeHost(params.Host) { + return "", &errortypes.BadInput{Message: "Invalid Host"} + } endpointParams := macros.EndpointTemplateParams{Host: params.Host, SourceId: params.SourceID, AccountID: params.AccountID} return macros.ResolveMacros(a.endpoint, endpointParams) } diff --git a/adapters/smartyads/smartyadstest/supplemental/invalid-host.json b/adapters/smartyads/smartyadstest/supplemental/invalid-host.json new file mode 100644 index 0000000000..10f8a8f6e8 --- /dev/null +++ b/adapters/smartyads/smartyadstest/supplemental/invalid-host.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "host": "evil.com/path?redirect=http://attacker.com#", + "sourceid": "partner", + "accountid": "testaccount" + } + } + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid Host", + "comparison": "literal" + } + ] +} diff --git a/adapters/tappx/params_test.go b/adapters/tappx/params_test.go index 2575dffed0..fd174f8309 100644 --- a/adapters/tappx/params_test.go +++ b/adapters/tappx/params_test.go @@ -35,7 +35,21 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915"}`, - `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"test.tappx.com"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host.example.com"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host.example.com:8080"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host-example.test"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"Host.Example.com"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"localhost:3000"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"/path"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"//evil.com"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host/path"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host?query=1"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host#fragment"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"user@host"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"https://host.com"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host:notaport"}`, + `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"host:8080:extra"}`, `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"test.tappx.com", "bidfloor":0.5}`, `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"test.tappx.com", "bidfloor":0.5, "mktag":"txmk-xxxxx-xxx-xxxx"}`, `{"tappxkey":"pub-12345-android-9876", "endpoint":"ZZ1INTERNALTEST149147915", "host":"test.tappx.com", "bidfloor":0.5, "bcid":["123"]}`, diff --git a/adapters/tappx/tappx.go b/adapters/tappx/tappx.go index d0052613e7..51738aa09c 100644 --- a/adapters/tappx/tappx.go +++ b/adapters/tappx/tappx.go @@ -17,6 +17,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) const TAPPX_BIDDER_VERSION = "1.6" @@ -118,7 +119,9 @@ func (a *TappxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt }}, []error{} } -// Builds enpoint url based on adapter-specific pub settings from imp.ext +// Builds endpoint url based on adapter-specific pub settings from imp.ext. +// NOTE: The deprecated "host" param (params.Host) is intentionally unused here. +// If it is ever reintroduced, it MUST be validated with urlutil.IsSafeHost to prevent SSRF. func (a *TappxAdapter) buildEndpointURL(params *openrtb_ext.ExtImpTappx, test int) (string, error) { if params.Endpoint == "" { @@ -132,7 +135,6 @@ func (a *TappxAdapter) buildEndpointURL(params *openrtb_ext.ExtImpTappx, test in Message: "Tappx key undefined", } } - isNewEndpoint, err := regexp.Match(`^(zz|vz)[0-9]{3,}([a-z]{2,3}|test)$`, []byte(params.Endpoint)) if err != nil { return "", &errortypes.BadInput{ @@ -141,8 +143,17 @@ func (a *TappxAdapter) buildEndpointURL(params *openrtb_ext.ExtImpTappx, test in } var tappxHost string if isNewEndpoint { + // Defense-in-depth: the runtime regex above is stricter than IsSafeHost, + // so this check is currently unreachable. It guards against future relaxation + // of the regex inadvertently allowing SSRF via subdomain injection. + if !urlutil.IsSafeHost(params.Endpoint) { + return "", &errortypes.BadInput{ + Message: "Invalid Tappx endpoint", + } + } tappxHost = params.Endpoint + ".pub.tappx.com/rtb/" } else { + // endpoint is used as a path segment on fixed domain: ssp.api.tappx.com/rtb/v2/{endpoint} tappxHost = "ssp.api.tappx.com/rtb/v2/" } diff --git a/adapters/tradplus/params_test.go b/adapters/tradplus/params_test.go index 394a8e7b84..7a537e911e 100644 --- a/adapters/tradplus/params_test.go +++ b/adapters/tradplus/params_test.go @@ -35,9 +35,13 @@ func TestInvalidParams(t *testing.T) { } var validParams = []string{ + `{"accountId": "11233"}`, `{"accountId": "11233", "zoneId": ""}`, - `{"accountId": "aaa", "zoneId": "us"}`, - `{"accountId": "aa", "accountId": "sin"}`, + `{"accountId": "11233", "zoneId": "host"}`, + `{"accountId": "aaa", "zoneId": "host.example.com"}`, + `{"accountId": "aa", "zoneId": "host-example.test"}`, + `{"accountId": "aaa", "zoneId": "Host.Example.com"}`, + `{"accountId": "aaa", "zoneId": "localhost"}`, } var invalidParams = []string{ @@ -50,4 +54,14 @@ var invalidParams = []string{ `{"accountId": null}`, `{"zoneId": "aaa"}`, `{"zoneId": null}`, + `{"accountId": "aaa", "zoneId": "/path"}`, + `{"accountId": "aaa", "zoneId": "//evil.com"}`, + `{"accountId": "aaa", "zoneId": "host/path"}`, + `{"accountId": "aaa", "zoneId": "host?query=1"}`, + `{"accountId": "aaa", "zoneId": "host#fragment"}`, + `{"accountId": "aaa", "zoneId": "user@host"}`, + `{"accountId": "aaa", "zoneId": "https://host.com"}`, + `{"accountId": "aaa", "zoneId": "host:notaport"}`, + `{"accountId": "aaa", "zoneId": "host:8080:extra"}`, + `{"accountId": "aaa", "zoneId": "host:8080"}`, } diff --git a/adapters/tradplus/tradplus.go b/adapters/tradplus/tradplus.go index 7e7b7a6ecd..4c1d08f404 100644 --- a/adapters/tradplus/tradplus.go +++ b/adapters/tradplus/tradplus.go @@ -13,6 +13,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -86,6 +87,9 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTradPlus, error) { } func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpTradPlus) (string, error) { + if params.ZoneID != "" && !urlutil.IsSafeHost(params.ZoneID) { + return "", &errortypes.BadInput{Message: "Invalid ZoneID"} + } endpointParams := macros.EndpointTemplateParams{ AccountID: params.AccountID, ZoneID: params.ZoneID, diff --git a/adapters/tradplus/tradplustest/supplemental/invalid-zoneid.json b/adapters/tradplus/tradplustest/supplemental/invalid-zoneid.json new file mode 100644 index 0000000000..75ebc22bd5 --- /dev/null +++ b/adapters/tradplus/tradplustest/supplemental/invalid-zoneid.json @@ -0,0 +1,25 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 50}] + }, + "ext": { + "bidder": { + "accountId": "testaccount", + "zoneId": "evil.com/path?redirect=http://attacker.com#" + } + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid ZoneID", + "comparison": "literal" + } + ] +} diff --git a/adapters/trafficgate/params_test.go b/adapters/trafficgate/params_test.go index a14f887dd9..0a0d34ea04 100644 --- a/adapters/trafficgate/params_test.go +++ b/adapters/trafficgate/params_test.go @@ -36,7 +36,12 @@ func TestInvalidParams(t *testing.T) { } var validParams = []string{ - `{"placementId": "11", "host": "example"}`, + `{"placementId": "11", "host": "host"}`, + `{"placementId": "11", "host": "host.example.com"}`, + `{"placementId": "11", "host": "host.example.com:8080"}`, + `{"placementId": "11", "host": "host-example.test"}`, + `{"placementId": "11", "host": "Host.Example.com"}`, + `{"placementId": "11", "host": "localhost:3000"}`, } var invalidParams = []string{ @@ -45,4 +50,13 @@ var invalidParams = []string{ `{"placement_id": 346, "host": ""}`, `{"placementID": "", "HOST": "example"}`, `{"placementId": 234}`, + `{"placementId": "11", "host": "/path"}`, + `{"placementId": "11", "host": "//evil.com"}`, + `{"placementId": "11", "host": "host/path"}`, + `{"placementId": "11", "host": "host?query=1"}`, + `{"placementId": "11", "host": "host#fragment"}`, + `{"placementId": "11", "host": "user@host"}`, + `{"placementId": "11", "host": "https://host.com"}`, + `{"placementId": "11", "host": "host:notaport"}`, + `{"placementId": "11", "host": "host:8080:extra"}`, } diff --git a/adapters/trafficgate/trafficgate.go b/adapters/trafficgate/trafficgate.go index ce72048ad9..741b70745f 100644 --- a/adapters/trafficgate/trafficgate.go +++ b/adapters/trafficgate/trafficgate.go @@ -13,6 +13,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type adapter struct { @@ -153,6 +154,9 @@ func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTrafficGate, error) Message: "Bidder parameters required", } } + if !urlutil.IsSafeHost(TrafficGateExt.Host) { + return nil, &errortypes.BadInput{Message: "Invalid Host"} + } return &TrafficGateExt, nil } diff --git a/adapters/trafficgate/trafficgatetest/supplemental/invalid-host.json b/adapters/trafficgate/trafficgatetest/supplemental/invalid-host.json new file mode 100644 index 0000000000..fa4589e99d --- /dev/null +++ b/adapters/trafficgate/trafficgatetest/supplemental/invalid-host.json @@ -0,0 +1,35 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placementId": "1", + "host": "evil.com/path?redirect=http://attacker.com#" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.test.app" + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid Host", + "comparison": "literal" + } + ] +} diff --git a/adapters/zeroclickfraud/params_test.go b/adapters/zeroclickfraud/params_test.go new file mode 100644 index 0000000000..14682e83bb --- /dev/null +++ b/adapters/zeroclickfraud/params_test.go @@ -0,0 +1,65 @@ +package zeroclickfraud + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +var validParams = []string{ + `{ "host": "host", "sourceId": 1 }`, + `{ "host": "host.example.com", "sourceId": 1 }`, + `{ "host": "host.example.com:8080", "sourceId": 1 }`, + `{ "host": "host-example.test", "sourceId": 1 }`, + `{ "host": "Host.Example.com", "sourceId": 1 }`, + `{ "host": "localhost:3000", "sourceId": 1 }`, +} + +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.BidderZeroClickFraud, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected ZeroClickFraud params: %s", validParam) + } + } +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{ "sourceId": 1 }`, + `{ "host": "host" }`, + `{ "host": "", "sourceId": 1 }`, + `{ "host": "/path", "sourceId": 1 }`, + `{ "host": "//evil.com", "sourceId": 1 }`, + `{ "host": "host/path", "sourceId": 1 }`, + `{ "host": "host?query=1", "sourceId": 1 }`, + `{ "host": "host#fragment", "sourceId": 1 }`, + `{ "host": "user@host", "sourceId": 1 }`, + `{ "host": "https://host.com", "sourceId": 1 }`, + `{ "host": "host:notaport", "sourceId": 1 }`, + `{ "host": "host:8080:extra", "sourceId": 1 }`, +} + +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.BidderZeroClickFraud, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} diff --git a/adapters/zeroclickfraud/zeroclickfraud.go b/adapters/zeroclickfraud/zeroclickfraud.go index 08d0040241..0bda7b3687 100644 --- a/adapters/zeroclickfraud/zeroclickfraud.go +++ b/adapters/zeroclickfraud/zeroclickfraud.go @@ -14,6 +14,7 @@ import ( "github.com/prebid/prebid-server/v4/macros" "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/prebid/prebid-server/v4/util/jsonutil" + "github.com/prebid/prebid-server/v4/util/urlutil" ) type ZeroClickFraudAdapter struct { @@ -149,7 +150,7 @@ func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpZeroClickFraud, erro } } - if len(zeroclickfraudExt.Host) < 1 { + if !urlutil.IsSafeHost(zeroclickfraudExt.Host) { return nil, &errortypes.BadInput{ Message: "Invalid/Missing Host", } diff --git a/adapters/zeroclickfraud/zeroclickfraudtest/supplemental/invalid-host.json b/adapters/zeroclickfraud/zeroclickfraudtest/supplemental/invalid-host.json new file mode 100644 index 0000000000..edd5ca65a2 --- /dev/null +++ b/adapters/zeroclickfraud/zeroclickfraudtest/supplemental/invalid-host.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "host": "evil.com/path?redirect=http://attacker.com#", + "sourceId": 123 + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid/Missing Host", + "comparison": "literal" + } + ] +} diff --git a/static/bidder-params/acuityads.json b/static/bidder-params/acuityads.json index bae86ad210..b5ccdf67d2 100644 --- a/static/bidder-params/acuityads.json +++ b/static/bidder-params/acuityads.json @@ -7,7 +7,8 @@ "host": { "type": "string", "description": "Network host to send request", - "minLength": 1 + "minLength": 1, + "pattern": "^[a-zA-Z0-9.-]+(:[0-9]+)?$" }, "accountid": { "type": "string", @@ -15,5 +16,8 @@ "minLength": 1 } }, - "required": ["host", "accountid"] -} \ No newline at end of file + "required": [ + "host", + "accountid" + ] +} diff --git a/static/bidder-params/adhese.json b/static/bidder-params/adhese.json index 14234a8bd1..ac6576c81d 100644 --- a/static/bidder-params/adhese.json +++ b/static/bidder-params/adhese.json @@ -7,6 +7,7 @@ "account": { "type": "string", "minLength": 1, + "pattern": "^[a-zA-Z0-9.-]+$", "description": "Your Adhese account name. If unknown, please contact your sales rep" }, "location": { diff --git a/static/bidder-params/bidmachine.json b/static/bidder-params/bidmachine.json index 819dc9b7e2..752461589a 100644 --- a/static/bidder-params/bidmachine.json +++ b/static/bidder-params/bidmachine.json @@ -1,28 +1,29 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Bidmachine Adapter Params", - "description": "A schema which validates params accepted by the Kidoz adapter", - "type": "object", - "properties": { - "host": { - "type": "string", - "minLength": 1, - "description": "Host" - }, - "path": { - "type": "string", - "minLength": 1, - "description": "URL path" - }, - "seller_id": { - "type": "string", - "minLength": 1, - "description": "Seller Identifier" - } + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Bidmachine Adapter Params", + "description": "A schema which validates params accepted by the Kidoz adapter", + "type": "object", + "properties": { + "host": { + "type": "string", + "minLength": 1, + "description": "Host", + "pattern": "^[a-zA-Z0-9.-]+(:[0-9]+)?$" }, - "required": [ - "host", - "path", - "seller_id" - ] + "path": { + "type": "string", + "minLength": 1, + "description": "URL path" + }, + "seller_id": { + "type": "string", + "minLength": 1, + "description": "Seller Identifier" + } + }, + "required": [ + "host", + "path", + "seller_id" + ] } diff --git a/static/bidder-params/kayzen.json b/static/bidder-params/kayzen.json index f2256c6b02..8383fac679 100644 --- a/static/bidder-params/kayzen.json +++ b/static/bidder-params/kayzen.json @@ -8,6 +8,7 @@ "zone": { "type": "string", "minLength": 1, + "pattern": "^[a-zA-Z0-9.-]+$", "description": "Zone ID" }, "exchange": { diff --git a/static/bidder-params/rediads.json b/static/bidder-params/rediads.json index 85c9e545a2..dbca954bba 100644 --- a/static/bidder-params/rediads.json +++ b/static/bidder-params/rediads.json @@ -11,7 +11,8 @@ "type": "string" }, "endpoint": { - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9.-]+$" } }, "required": ["account_id"] diff --git a/static/bidder-params/relevantdigital.json b/static/bidder-params/relevantdigital.json index a3c1ad027d..6c6cdca051 100644 --- a/static/bidder-params/relevantdigital.json +++ b/static/bidder-params/relevantdigital.json @@ -1,33 +1,34 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Relevant Digital Adapter Params", - "description": "A schema which validates params accepted by the Relevant Digital adapter", - "type": "object", - "properties": { - "accountId": { - "type": "string", - "description": "An ID which identifies the Relevant Digital account ID" - }, - "placementId": { - "type": "string", - "description": "An ID which identifies the Relevant Digital placement ID" - }, - "pbsHost": { - "type": "string", - "description": "Prebid Server Host supplied by Relevant Digital" - }, - "pbsBufferMs": { - "type": "number", - "description": "TMax buffer, default is 250" - }, - "useSourceBidderCode": { - "type": "boolean", - "description": "Use the bidder code of the actual server-side bidder in bid responses" - } + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Relevant Digital Adapter Params", + "description": "A schema which validates params accepted by the Relevant Digital adapter", + "type": "object", + "properties": { + "accountId": { + "type": "string", + "description": "An ID which identifies the Relevant Digital account ID" }, - "required": [ - "accountId", - "placementId", - "pbsHost" - ] + "placementId": { + "type": "string", + "description": "An ID which identifies the Relevant Digital placement ID" + }, + "pbsHost": { + "type": "string", + "description": "Prebid Server Host supplied by Relevant Digital", + "pattern": "^(https?://)?[a-zA-Z0-9.-]+(:[0-9]+)?$" + }, + "pbsBufferMs": { + "type": "number", + "description": "TMax buffer, default is 250" + }, + "useSourceBidderCode": { + "type": "boolean", + "description": "Use the bidder code of the actual server-side bidder in bid responses" + } + }, + "required": [ + "accountId", + "placementId", + "pbsHost" + ] } diff --git a/static/bidder-params/smartyads.json b/static/bidder-params/smartyads.json index 629fdde326..7a6518b263 100644 --- a/static/bidder-params/smartyads.json +++ b/static/bidder-params/smartyads.json @@ -6,7 +6,8 @@ "properties": { "host": { "type": "string", - "description": "Network host to send request" + "description": "Network host to send request", + "pattern": "^[a-zA-Z0-9.-]+(:[0-9]+)?$" }, "sourceid": { "type": "string", @@ -17,5 +18,9 @@ "description": "Account id" } }, - "required": ["host", "sourceid", "accountid"] -} \ No newline at end of file + "required": [ + "host", + "sourceid", + "accountid" + ] +} diff --git a/static/bidder-params/tappx.json b/static/bidder-params/tappx.json index 77eb4eea93..f2dfe52c90 100644 --- a/static/bidder-params/tappx.json +++ b/static/bidder-params/tappx.json @@ -1,43 +1,47 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Tappx Adapter Params", - "description": "A schema which validates params accepted by the Tappx adapter", - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "Tappx host" - }, - "tappxkey": { - "type": "string", - "description": "An ID which identifies the adunit" - }, - "mktag": { - "type": "string", - "description": "Minimum bid for this impression expressed in CPM (USD)" - }, - "endpoint": { - "type": "string", - "description": "Endpoint provided to publisher" - }, - "bidfloor": { - "type": "number", - "description": "Minimum bid for this impression expressed in CPM (USD)" - }, - "bcid": { - "type": "array", - "description": "Block list of CID", - "items": { - "type": "string" - } - }, - "bcrid": { - "type": "array", - "description": "Block list of CRID", - "items": { - "type": "string" - } - } - }, - "required": ["tappxkey","endpoint"] + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Tappx Adapter Params", + "description": "A schema which validates params accepted by the Tappx adapter", + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "Tappx host (DEPRECATED - unused)" + }, + "tappxkey": { + "type": "string", + "description": "An ID which identifies the adunit" + }, + "mktag": { + "type": "string", + "description": "Minimum bid for this impression expressed in CPM (USD)" + }, + "endpoint": { + "type": "string", + "minLength": 1, + "description": "Endpoint provided to publisher" + }, + "bidfloor": { + "type": "number", + "description": "Minimum bid for this impression expressed in CPM (USD)" + }, + "bcid": { + "type": "array", + "description": "Block list of CID", + "items": { + "type": "string" + } + }, + "bcrid": { + "type": "array", + "description": "Block list of CRID", + "items": { + "type": "string" + } + } + }, + "required": [ + "tappxkey", + "endpoint" + ] } diff --git a/static/bidder-params/tradplus.json b/static/bidder-params/tradplus.json index 2f568bad07..d463aa3f01 100644 --- a/static/bidder-params/tradplus.json +++ b/static/bidder-params/tradplus.json @@ -11,7 +11,8 @@ }, "zoneId": { "type": "string", - "description": "Zone ID" + "description": "Zone ID", + "pattern": "^[a-zA-Z0-9.-]*$" } }, "required": [ diff --git a/static/bidder-params/trafficgate.json b/static/bidder-params/trafficgate.json index 8b7ff3bee3..e6d8e7b793 100644 --- a/static/bidder-params/trafficgate.json +++ b/static/bidder-params/trafficgate.json @@ -12,12 +12,16 @@ "host": { "type": "string", "minLength": 1, - "description": "An ID which identifies the TrafficGate host" + "description": "An ID which identifies the TrafficGate host", + "pattern": "^[a-zA-Z0-9.-]+(:[0-9]+)?$" }, "customParams": { "type": "object", "description": "User-defined targeting key-value pairs." } }, - "required" : [ "placementId", "host" ] + "required": [ + "placementId", + "host" + ] } diff --git a/static/bidder-params/zeroclickfraud.json b/static/bidder-params/zeroclickfraud.json index 1c5e3c633b..5a306bad3e 100644 --- a/static/bidder-params/zeroclickfraud.json +++ b/static/bidder-params/zeroclickfraud.json @@ -2,18 +2,21 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "ZeroClickFraud Adapter Params", "description": "A schema which validates params accepted by the ZeroClickFraud adapter", - "type": "object", "properties": { - "sourceId": { - "type": "integer", - "minimum": 1, - "description": "Website Source Id" - }, - "host": { - "type": "string", - "description": "Network Host to request from" - } + "sourceId": { + "type": "integer", + "minimum": 1, + "description": "Website Source Id" + }, + "host": { + "type": "string", + "description": "Network Host to request from", + "pattern": "^[a-zA-Z0-9.-]+(:[0-9]+)?$" + } }, - "required": ["host", "sourceId"] + "required": [ + "host", + "sourceId" + ] } diff --git a/util/urlutil/security.go b/util/urlutil/security.go new file mode 100644 index 0000000000..51b9b5a6b9 --- /dev/null +++ b/util/urlutil/security.go @@ -0,0 +1,12 @@ +package urlutil + +import "regexp" + +var safeHostPattern = regexp.MustCompile(`^[a-zA-Z0-9.-]+(:[0-9]+)?$`) + +// IsSafeHost returns true for bare hostnames with an optional port. +// It intentionally rejects URL control characters such as '/', '?', '#', and '@' +// so user-supplied host values cannot rewrite the outbound request URL. +func IsSafeHost(host string) bool { + return safeHostPattern.MatchString(host) +} diff --git a/util/urlutil/security_test.go b/util/urlutil/security_test.go new file mode 100644 index 0000000000..d974f7cfa2 --- /dev/null +++ b/util/urlutil/security_test.go @@ -0,0 +1,68 @@ +package urlutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsSafeHost(t *testing.T) { + testCases := []struct { + name string + host string + want bool + }{ + { + name: "hostname", + host: "example.com", + want: true, + }, + { + name: "subdomain", + host: "api-us", + want: true, + }, + { + name: "hostname with port", + host: "example.com:8080", + want: true, + }, + { + name: "empty", + host: "", + want: false, + }, + { + name: "path injection", + host: "127.0.0.1:6060/debug/pprof", + want: false, + }, + { + name: "fragment injection", + host: "127.0.0.1:6060#", + want: false, + }, + { + name: "query injection", + host: "example.com?x=1", + want: false, + }, + { + name: "userinfo injection", + host: "example.com@127.0.0.1", + want: false, + }, + { + name: "scheme injection", + host: "http://127.0.0.1", + want: false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := IsSafeHost(test.host) + assert.Equal(t, test.want, result) + }) + } +} From e56ddb2fb29d18fe3d8c67eca45230fc7db1a481 Mon Sep 17 00:00:00 2001 From: pedjoni8 <32640009+pedjoni8@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:25:54 +0200 Subject: [PATCH 225/272] New Adapter: targetVideo (#4593) --- adapters/targetVideo/params_test.go | 45 ++++++ adapters/targetVideo/targetvideo.go | 142 ++++++++++++++++++ adapters/targetVideo/targetvideo_test.go | 19 +++ .../targetvideotest/exemplary/app-video.json | 116 ++++++++++++++ .../targetvideotest/exemplary/site-video.json | 122 +++++++++++++++ .../targetvideotest/supplemental/204.json | 85 +++++++++++ .../targetvideotest/supplemental/400.json | 90 +++++++++++ .../supplemental/ext-bidder-error.json | 37 +++++ .../supplemental/no_seatbid.json | 91 +++++++++++ .../overwrite-stored-request.json | 127 ++++++++++++++++ .../supplemental/preserve-imp-ext-fields.json | 130 ++++++++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_targetvideo.go | 8 + static/bidder-info/targetVideo.yaml | 17 +++ static/bidder-params/targetVideo.json | 14 ++ 16 files changed, 1047 insertions(+) create mode 100644 adapters/targetVideo/params_test.go create mode 100644 adapters/targetVideo/targetvideo.go create mode 100644 adapters/targetVideo/targetvideo_test.go create mode 100644 adapters/targetVideo/targetvideotest/exemplary/app-video.json create mode 100644 adapters/targetVideo/targetvideotest/exemplary/site-video.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/204.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/400.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/ext-bidder-error.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/no_seatbid.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/overwrite-stored-request.json create mode 100644 adapters/targetVideo/targetvideotest/supplemental/preserve-imp-ext-fields.json create mode 100644 openrtb_ext/imp_targetvideo.go create mode 100644 static/bidder-info/targetVideo.yaml create mode 100644 static/bidder-params/targetVideo.json diff --git a/adapters/targetVideo/params_test.go b/adapters/targetVideo/params_test.go new file mode 100644 index 0000000000..1839f0bbe6 --- /dev/null +++ b/adapters/targetVideo/params_test.go @@ -0,0 +1,45 @@ +package targetVideo + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas") + + for _, validParam := range validParams { + assert.NoError(t, validator.Validate(openrtb_ext.BidderTargetVideo, json.RawMessage(validParam)), + "Schema rejected targetVideo params: %s", validParam) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json-schemas") + + for _, invalidParam := range invalidParams { + assert.Error(t, validator.Validate(openrtb_ext.BidderTargetVideo, json.RawMessage(invalidParam)), + "Schema should have rejected unexpected params: %s", invalidParam) + } +} + +var validParams = []string{ + `{"placementId":846}`, + `{"placementId":"846"}`, +} + +var invalidParams = []string{ + `null`, + `nil`, + `undefined`, + `{"placementId": "%9"}`, + `{"publisherId": "as9""}`, + `{"placementId": true}`, + `{"placementId": ""}`, +} diff --git a/adapters/targetVideo/targetvideo.go b/adapters/targetVideo/targetvideo.go new file mode 100644 index 0000000000..a9649f0ddb --- /dev/null +++ b/adapters/targetVideo/targetvideo.go @@ -0,0 +1,142 @@ +package targetVideo + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errors []error + totalImps := len(request.Imp) + adapterRequests := make([]*adapters.RequestData, 0, totalImps) + + // Split multi-imp request into multiple ad server requests. SRA is currently not recommended. + for i := 0; i < totalImps; i++ { + adapterReq, err := a.makeRequest(*request, request.Imp[i]) + if err != nil { + errors = append(errors, err) + continue + } + adapterRequests = append(adapterRequests, adapterReq) + } + + return adapterRequests, errors +} + +func (a *adapter) makeRequest(request openrtb2.BidRequest, imp openrtb2.Imp) (*adapters.RequestData, error) { + + // For now, this adapter sends one imp per request, but we still + // iterate over all imps in the request to perform the required + // imp.ext transformation. + request.Imp = []openrtb2.Imp{imp} + + for i := range request.Imp { + + var extBidder adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &extBidder); err != nil { + return nil, &errortypes.BadInput{Message: "Invalid ext.bidder"} + } + var extImpTargetVideo openrtb_ext.ExtImpTargetVideo + if err := jsonutil.Unmarshal(extBidder.Bidder, &extImpTargetVideo); err != nil { + return nil, err + } + + prebid := extBidder.Prebid + if prebid == nil { + prebid = &openrtb_ext.ExtImpPrebid{} + } + if prebid.StoredRequest == nil { + prebid.StoredRequest = &openrtb_ext.ExtStoredRequest{} + } + prebid.StoredRequest.ID = fmt.Sprintf("%d", extImpTargetVideo.PlacementId) + + var extMap map[string]json.RawMessage + if err := jsonutil.Unmarshal(imp.Ext, &extMap); err != nil { + return nil, &errortypes.BadInput{Message: fmt.Sprintf("error parsing imp.ext, err: %s", err)} + } + delete(extMap, "bidder") + + prebidRaw, err := jsonutil.Marshal(prebid) + if err != nil { + return nil, &errortypes.BadInput{Message: fmt.Sprintf("error building imp.ext.prebid, err: %s", err)} + } + extMap["prebid"] = prebidRaw + + extRaw, err := jsonutil.Marshal(extMap) + if err != nil { + return nil, &errortypes.BadInput{Message: fmt.Sprintf("error building imp.ext, err: %s", err)} + } + + request.Imp[i].Ext = extRaw + + } + + reqJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + return &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(httpRes) { + return nil, nil + } + if statusError := adapters.CheckResponseStatusCodeForErrors(httpRes); statusError != nil { + return nil, []error{statusError} + } + + bidResp, errResp := prepareBidResponse(httpRes.Body) + if errResp != nil { + return nil, []error{errResp} + } + + br := adapters.NewBidderResponse() + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bid := sb.Bid[i] + br.Bids = append(br.Bids, &adapters.TypedBid{Bid: &bid, BidType: openrtb_ext.BidTypeVideo}) + br.Currency = bidResp.Cur + } + } + return br, nil +} + +func prepareBidResponse(body []byte) (openrtb2.BidResponse, error) { + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(body, &response); err != nil { + return response, err + } + return response, nil +} + +func Builder(bidderName openrtb_ext.BidderName, cfg config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: cfg.Endpoint, + } + return bidder, nil +} diff --git a/adapters/targetVideo/targetvideo_test.go b/adapters/targetVideo/targetvideo_test.go new file mode 100644 index 0000000000..39ddd9d82b --- /dev/null +++ b/adapters/targetVideo/targetvideo_test.go @@ -0,0 +1,19 @@ +package targetVideo + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderTargetVideo, config.Adapter{ + Endpoint: "http://localhost/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + require.NoError(t, buildErr, "Builder returned unexpected error") + + adapterstest.RunJSONBidderTest(t, "targetvideotest", bidder) +} diff --git a/adapters/targetVideo/targetvideotest/exemplary/app-video.json b/adapters/targetVideo/targetvideotest/exemplary/app-video.json new file mode 100644 index 0000000000..88557a1e46 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/exemplary/app-video.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "app": { + "id": "appID", + "publisher": { + "id": "uniq_pub_id" + } + }, + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + } + } + } + ], + "device": { + "ua": "test-user-agent" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "app": { + "id": "appID", + "publisher": { + "id": "uniq_pub_id" + } + }, + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent" + }, + "cur": ["EUR"] + }, + "impIDs":["test-imp-id-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-video", + "seatbid": [ + { + "seat": "targetVideo", + "bid": [ + { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adid": "12345678", + "adm": "test-imp-id-video", + "cid": "789", + "crid": "12345678", + "h": 360, + "w": 640 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids" : [{ + "bid": { + "id": "randomID", + "adid": "12345678", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "crid": "12345678", + "cid": "789", + "h": 360, + "w": 640 + }, + "type": "video" + }] + } + ] +} diff --git a/adapters/targetVideo/targetvideotest/exemplary/site-video.json b/adapters/targetVideo/targetvideotest/exemplary/site-video.json new file mode 100644 index 0000000000..fcb6e34ed3 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/exemplary/site-video.json @@ -0,0 +1,122 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs":["test-imp-id-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-video", + "seatbid": [ + { + "seat": "targetVideo", + "bid": [ + { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "cid": "789", + "crid": "12345678", + "h": 360, + "w": 640 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids" : [{ + "bid": { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "crid": "12345678", + "cid": "789", + "h": 360, + "w": 640 + }, + "type": "video" + }] + } + ] +} diff --git a/adapters/targetVideo/targetvideotest/supplemental/204.json b/adapters/targetVideo/targetvideotest/supplemental/204.json new file mode 100644 index 0000000000..c64d797b32 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/204.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs":["test-imp-id-video"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/targetVideo/targetvideotest/supplemental/400.json b/adapters/targetVideo/targetvideotest/supplemental/400.json new file mode 100644 index 0000000000..e69838a3c1 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/400.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs":["test-imp-id-video"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/targetVideo/targetvideotest/supplemental/ext-bidder-error.json b/adapters/targetVideo/targetvideotest/supplemental/ext-bidder-error.json new file mode 100644 index 0000000000..009d397e3f --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/ext-bidder-error.json @@ -0,0 +1,37 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "Invalid ext.bidder", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": "invalid-ext" + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/targetVideo/targetvideotest/supplemental/no_seatbid.json b/adapters/targetVideo/targetvideotest/supplemental/no_seatbid.json new file mode 100644 index 0000000000..73321a5838 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/no_seatbid.json @@ -0,0 +1,91 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs":["test-imp-id-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [{ + "currency": "USD" + }] +} diff --git a/adapters/targetVideo/targetvideotest/supplemental/overwrite-stored-request.json b/adapters/targetVideo/targetvideotest/supplemental/overwrite-stored-request.json new file mode 100644 index 0000000000..1d611a7810 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/overwrite-stored-request.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + }, + "prebid": { + "storedrequest": { + "id": "existing-stored-req" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + } + } + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs": ["test-imp-id-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-video", + "seatbid": [ + { + "seat": "targetVideo", + "bid": [ + { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "cid": "789", + "crid": "12345678", + "h": 360, + "w": 640 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [{ + "bid": { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "crid": "12345678", + "cid": "789", + "h": 360, + "w": 640 + }, + "type": "video" + }] + } + ] +} diff --git a/adapters/targetVideo/targetvideotest/supplemental/preserve-imp-ext-fields.json b/adapters/targetVideo/targetvideotest/supplemental/preserve-imp-ext-fields.json new file mode 100644 index 0000000000..4db9285083 --- /dev/null +++ b/adapters/targetVideo/targetvideotest/supplemental/preserve-imp-ext-fields.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "cur": ["EUR"], + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "placementId": "77777" + }, + "prebid": { + "is_rewarded_inventory": 1 + }, + "tid": "some-transaction-id", + "gpid": "/1234/main-player" + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "http://localhost/pbs", + "body": { + "id": "test-request-id-video", + "imp": [ + { + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "prebid": { + "storedrequest": { + "id": "77777" + }, + "is_rewarded_inventory": 1 + }, + "tid": "some-transaction-id", + "gpid": "/1234/main-player" + } + } + ], + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "site": { + "domain": "www.publisher.com", + "page": "http://www.publisher.com/some/path", + "ext": { + "amp": 0 + } + }, + "cur": ["EUR"] + }, + "impIDs": ["test-imp-id-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-video", + "seatbid": [ + { + "seat": "targetVideo", + "bid": [ + { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "cid": "789", + "crid": "12345678", + "h": 360, + "w": 640 + } + ] + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [{ + "bid": { + "id": "randomID", + "impid": "test-imp-id-video", + "price": 5.5, + "adm": "test-imp-id-video", + "crid": "12345678", + "cid": "789", + "h": 360, + "w": 640 + }, + "type": "video" + }] + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 2d6526a190..91a1325e30 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -228,6 +228,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/taboola" "github.com/prebid/prebid-server/v4/adapters/tadvertising_blis" "github.com/prebid/prebid-server/v4/adapters/tappx" + "github.com/prebid/prebid-server/v4/adapters/targetVideo" "github.com/prebid/prebid-server/v4/adapters/teads" "github.com/prebid/prebid-server/v4/adapters/telaria" "github.com/prebid/prebid-server/v4/adapters/teqblaze" @@ -501,6 +502,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderTaboola: taboola.Builder, openrtb_ext.BidderTAdvertisingBlis: tadvertising_blis.Builder, openrtb_ext.BidderTappx: tappx.Builder, + openrtb_ext.BidderTargetVideo: targetVideo.Builder, openrtb_ext.BidderTeads: teads.Builder, openrtb_ext.BidderTelaria: telaria.Builder, openrtb_ext.BidderTeqBlaze: teqblaze.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 9e9cfaa761..35dbf5e95f 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -246,6 +246,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderTaboola, BidderTAdvertisingBlis, BidderTappx, + BidderTargetVideo, BidderTeads, BidderTelaria, BidderTeqBlaze, @@ -623,6 +624,7 @@ const ( BidderTaboola BidderName = "taboola" BidderTAdvertisingBlis BidderName = "tadvertising_blis" BidderTappx BidderName = "tappx" + BidderTargetVideo BidderName = "targetVideo" BidderTeads BidderName = "teads" BidderTelaria BidderName = "telaria" BidderTeqBlaze BidderName = "teqblaze" diff --git a/openrtb_ext/imp_targetvideo.go b/openrtb_ext/imp_targetvideo.go new file mode 100644 index 0000000000..c13b8a42aa --- /dev/null +++ b/openrtb_ext/imp_targetvideo.go @@ -0,0 +1,8 @@ +package openrtb_ext + +import "github.com/prebid/prebid-server/v4/util/jsonutil" + +// ExtImpTargetVideo defines the contract for bidrequest.imp[i].ext.prebid.bidder.targetVideo +type ExtImpTargetVideo struct { + PlacementId jsonutil.StringInt `json:"placementId,omitempty"` +} diff --git a/static/bidder-info/targetVideo.yaml b/static/bidder-info/targetVideo.yaml new file mode 100644 index 0000000000..decc110db3 --- /dev/null +++ b/static/bidder-info/targetVideo.yaml @@ -0,0 +1,17 @@ +endpoint: "https://pbs.prebrid.tv/openrtb2/auction" +geoscope: + - global +maintainer: + email: "contact@target-video.com" +gvlVendorID: 786 +capabilities: + app: + mediaTypes: + - video + site: + mediaTypes: + - video +userSync: + redirect: + url: "https://pbs.prebrid.tv/user_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "[TVUID]" diff --git a/static/bidder-params/targetVideo.json b/static/bidder-params/targetVideo.json new file mode 100644 index 0000000000..86c73b4bb7 --- /dev/null +++ b/static/bidder-params/targetVideo.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TargetVideo Adapter Params", + "description": "A schema which validates params accepted by the TargetVideo adapter", + "type": "object", + "properties": { + "placementId": { + "type": ["integer", "string"], + "pattern": "^\\d+$", + "description": "An ID which identifies this placement of the impression" + } + }, + "required": ["placementId"] +} From 1649c14527a57caaae798a19d4595beb31907d74 Mon Sep 17 00:00:00 2001 From: quietPusher <129727954+quietPusher@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:39:19 +0200 Subject: [PATCH 226/272] New Adapter: pgamrtb - Limelight Alias (#4714) Co-authored-by: apykhteyev <alex@project-limelight.com> Co-authored-by: mderevyanko <mderevyanko24@gmail.com> --- static/bidder-info/pgamrtb.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/pgamrtb.yaml diff --git a/static/bidder-info/pgamrtb.yaml b/static/bidder-info/pgamrtb.yaml new file mode 100644 index 0000000000..718c341d54 --- /dev/null +++ b/static/bidder-info/pgamrtb.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.pgamrtb.com/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" From 48fb440b92417c58b928e5bb9c2430411e759fda Mon Sep 17 00:00:00 2001 From: anishb-ms <122366082+anishb-ms@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:35:30 +0530 Subject: [PATCH 227/272] Parameterize Dockerfile base image (#4817) --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6c0295688b..cc6a3fdf1c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,7 @@ -FROM ubuntu:22.04 AS build +# BASE_IMAGE allows overriding the base image so the build can pull from an +# internal mirror when docker.io is unreachable. Defaults to upstream ubuntu:22.04. +ARG BASE_IMAGE=ubuntu:22.04 +FROM ${BASE_IMAGE} AS build RUN apt-get update && \ apt-get -y upgrade && \ apt-get install -y --no-install-recommends wget ca-certificates @@ -26,7 +29,7 @@ ARG TEST="true" RUN if [ "$TEST" != "false" ]; then ./validate.sh ; fi RUN go build -mod=vendor -ldflags "-X github.com/prebid/prebid-server/v4/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/v4/version.Rev=`git rev-parse HEAD`" . -FROM ubuntu:22.04 AS release +FROM ${BASE_IMAGE} AS release LABEL maintainer="hans.hjort@xandr.com" WORKDIR /usr/local/bin/ COPY --from=build /app/prebid-server . From fc0c406359ea43ddc2166e91c5c7f835f588cb56 Mon Sep 17 00:00:00 2001 From: linux019 <anode.dev@gmail.com> Date: Tue, 9 Jun 2026 16:19:52 +0300 Subject: [PATCH 228/272] Adagio: Fix usersync URL (#4716) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- static/bidder-info/adagio.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/adagio.yaml b/static/bidder-info/adagio.yaml index 849665697b..8dbdf879e8 100644 --- a/static/bidder-info/adagio.yaml +++ b/static/bidder-info/adagio.yaml @@ -7,7 +7,7 @@ endpoint: "https://mp-REGION.4dex.io/pbserver" userSync: iframe: - url: "https://u-REGION.4dex.io/pbserver/usync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + url: "https://u-REGION.4dex.io/pbserver/usync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" userMacro: "{UID}" disabled: true From b814614609a9fb415b1f6d7542885998fd47cfbf Mon Sep 17 00:00:00 2001 From: "Adserver.Online" <61009237+adserver-online@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:31:40 +0300 Subject: [PATCH 229/272] New Adapter: Adklip - Aso alias (#4581) --- static/bidder-info/adklip.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/bidder-info/adklip.yaml diff --git a/static/bidder-info/adklip.yaml b/static/bidder-info/adklip.yaml new file mode 100644 index 0000000000..89a7868fc3 --- /dev/null +++ b/static/bidder-info/adklip.yaml @@ -0,0 +1,8 @@ +aliasOf: aso +endpoint: "https://srv.adklip.net/pbs/bidder?zid={{.ZoneID}}" +maintainer: + email: "support@adklip.com" +userSync: + redirect: + url: "https://track.adklip.net/sync/v2?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usp={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "{uid}" From 5efee055df1557021bd891f9d80d40f7d4332b9e Mon Sep 17 00:00:00 2001 From: selectmediaPrebid <prebid@selectmedia.asia> Date: Tue, 9 Jun 2026 17:03:29 +0300 Subject: [PATCH 230/272] New Adapter: Selectmedia (#4769) --- static/bidder-info/selectmedia.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 static/bidder-info/selectmedia.yaml diff --git a/static/bidder-info/selectmedia.yaml b/static/bidder-info/selectmedia.yaml new file mode 100644 index 0000000000..752c5ddb6f --- /dev/null +++ b/static/bidder-info/selectmedia.yaml @@ -0,0 +1,26 @@ +disabled: true +# We have the following regional endpoint domains: 'us-east' - for US_EAST, 'eu' - for EU +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +aliasOf: "teqblaze" +endpoint: "https://#{REGION}#.zxyvrtd.com/pserver" +gvlVendorID: 775 +maintainer: + email: "prebid@selectmedia.asia" +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://sync.zxyvrtd.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://sync.zxyvrtd.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file From f455d83a6134982e03ef32f0b7fa4d6f0ca6949e Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:14:34 +0200 Subject: [PATCH 231/272] New Adapter: Native Agents (#4745) --- static/bidder-info/ntvagents.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 static/bidder-info/ntvagents.yaml diff --git a/static/bidder-info/ntvagents.yaml b/static/bidder-info/ntvagents.yaml new file mode 100644 index 0000000000..1b34a11c13 --- /dev/null +++ b/static/bidder-info/ntvagents.yaml @@ -0,0 +1,11 @@ +aliasOf: "teqblaze" +endpoint: "https://endpoint1.nativeagents.ai/pserver" +maintainer: + email: "prebid@nativeagents.ai" +userSync: + redirect: + url: "https://sync.nativeagents.ai/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://sync.nativeagents.ai/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 09313bef64e5961febdcd05794819dc826294c58 Mon Sep 17 00:00:00 2001 From: anzuprebid <prebid@anzu.io> Date: Tue, 9 Jun 2026 17:38:56 +0300 Subject: [PATCH 232/272] New Adapter: Anzu SSP (#4778) --- static/bidder-info/anzuSSP.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 static/bidder-info/anzuSSP.yaml diff --git a/static/bidder-info/anzuSSP.yaml b/static/bidder-info/anzuSSP.yaml new file mode 100644 index 0000000000..75aea96cab --- /dev/null +++ b/static/bidder-info/anzuSSP.yaml @@ -0,0 +1,16 @@ +aliasOf: "teqblaze" +endpoint: "http://endpoint.anzumarketplace.com/pserver" +maintainer: + email: "prebid@anzu.io" +capabilities: + site: + mediaTypes: + - banner + - video + - native + + app: + mediaTypes: + - banner + - video + - native \ No newline at end of file From 10a021b9de81ac0df8e191f20497dc8aaf22a749 Mon Sep 17 00:00:00 2001 From: Gena <g.moroz@adtelligent.com> Date: Tue, 9 Jun 2026 17:34:35 +0200 Subject: [PATCH 233/272] Indicue: Set GVL vendor ID to 0 (#4709) --- static/bidder-info/indicue.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/indicue.yaml b/static/bidder-info/indicue.yaml index 0548d0ed59..b6b2bccc80 100644 --- a/static/bidder-info/indicue.yaml +++ b/static/bidder-info/indicue.yaml @@ -2,7 +2,7 @@ aliasOf: adtelligent endpoint: "http://ghb.console.indicue.com/pbs/ortb" maintainer: email: "ops@indicue.com" -gvlVendorID: 410 +gvlVendorID: 0 userSync: # Indicue ssp supports user syncing, but requires configuration by the host. contact this # bidder directly at the email address in this file to ask about enabling user sync. From e02a53a744d3bc106a4542efa8c895a3ff047234 Mon Sep 17 00:00:00 2001 From: Boris Yu <admin@xdevel.info> Date: Tue, 9 Jun 2026 21:42:41 +0300 Subject: [PATCH 234/272] Displayio: Add audio and native support (#4728) Co-authored-by: Roman G <46111871+rgushel@users.noreply.github.com> Co-authored-by: linux019 <anode.dev@gmail.com> --- adapters/displayio/displayio.go | 10 +- .../displayiotest/exemplary/simple-audio.json | 116 ++++++++++++++++++ .../exemplary/simple-native.json | 114 +++++++++++++++++ .../supplemental/unexpected-media-type.json | 2 +- static/bidder-info/displayio.yaml | 6 +- 5 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 adapters/displayio/displayiotest/exemplary/simple-audio.json create mode 100644 adapters/displayio/displayiotest/exemplary/simple-native.json diff --git a/adapters/displayio/displayio.go b/adapters/displayio/displayio.go index 2eff41e71d..93b9b8bc4f 100644 --- a/adapters/displayio/displayio.go +++ b/adapters/displayio/displayio.go @@ -130,7 +130,7 @@ func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, _ *adapte var bidResp openrtb2.BidResponse if err := jsonutil.Unmarshal(responseData.Body, &bidResp); err != nil { - msg := fmt.Sprintf("Bad server response: %d", err) + msg := fmt.Sprintf("Bad server response: %v", err) return nil, []error{&errortypes.BadServerResponse{Message: msg}} } @@ -178,8 +178,14 @@ func getBidMediaTypeFromMtype(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { return openrtb_ext.BidTypeBanner, nil case openrtb2.MarkupVideo: return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil default: - return "", fmt.Errorf("unexpected media type for bid: %s", bid.ImpID) + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported MType %d", bid.MType), + } } } diff --git a/adapters/displayio/displayiotest/exemplary/simple-audio.json b/adapters/displayio/displayiotest/exemplary/simple-audio.json new file mode 100644 index 0000000000..e531760064 --- /dev/null +++ b/adapters/displayio/displayiotest/exemplary/simple-audio.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "app": { + "id": "1011" + }, + "id": "requestId10111011101110111011", + "imp": [ + { + "audio": { + "mimes": [ + "audio/mpeg" + ] + }, + "bidfloor": 0.5, + "bidfloorcur": "USD", + "id": "impId10111011101110111011", + "ext": { + "bidder": { + "placementId": "1011", + "publisherId": "101", + "inventoryId": "1011" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://adapter.endpoint/?macro=101", + "body": { + "app": { + "id": "1011" + }, + "id": "requestId10111011101110111011", + "imp": [ + { + "audio": { + "mimes": [ + "audio/mpeg" + ] + }, + "bidfloor": 0.5, + "bidfloorcur": "USD", + "id": "impId10111011101110111011", + "ext": { + "bidder": { + "placementId": "1011", + "publisherId": "101", + "inventoryId": "1011" + } + } + } + ], + "ext": { + "displayio": { + "placementId": "1011", + "inventoryId": "1011" + } + } + }, + "impIDs": [ + "impId10111011101110111011" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "requestId10111011101110111011", + "seatbid": [ + { + "bid": [ + { + "id": "12345", + "impid": "impId10111011101110111011", + "price": 2, + "adm": "<?xml/>", + "adid": "12235", + "adomain": [ + "domain.test" + ], + "mtype": 3 + } + ], + "seat": "displayio123", + "group": 1 + } + ], + "bidid": "test123", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "12345", + "impid": "impId10111011101110111011", + "price": 2, + "adm": "<?xml/>", + "adid": "12235", + "adomain": [ + "domain.test" + ], + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/displayio/displayiotest/exemplary/simple-native.json b/adapters/displayio/displayiotest/exemplary/simple-native.json new file mode 100644 index 0000000000..47a13e57e5 --- /dev/null +++ b/adapters/displayio/displayiotest/exemplary/simple-native.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "app": { + "id": "1011" + }, + "id": "requestId10111011101110111011", + "imp": [ + { + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"w\":480,\"h\":320}}]}", + "ver": "1.1" + }, + "bidfloor": 0.5, + "bidfloorcur": "USD", + "id": "impId10111011101110111011", + "ext": { + "bidder": { + "placementId": "1011", + "publisherId": "101", + "inventoryId": "1011" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://adapter.endpoint/?macro=101", + "body": { + "app": { + "id": "1011" + }, + "id": "requestId10111011101110111011", + "imp": [ + { + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":100}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"w\":480,\"h\":320}}]}", + "ver": "1.1" + }, + "bidfloor": 0.5, + "bidfloorcur": "USD", + "id": "impId10111011101110111011", + "ext": { + "bidder": { + "placementId": "1011", + "publisherId": "101", + "inventoryId": "1011" + } + } + } + ], + "ext": { + "displayio": { + "placementId": "1011", + "inventoryId": "1011" + } + } + }, + "impIDs": [ + "impId10111011101110111011" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "requestId10111011101110111011", + "seatbid": [ + { + "bid": [ + { + "id": "12345", + "impid": "impId10111011101110111011", + "price": 2, + "adm": "{}", + "adid": "12235", + "adomain": [ + "domain.test" + ], + "mtype": 4 + } + ], + "seat": "displayio123", + "group": 1 + } + ], + "bidid": "test123", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "12345", + "impid": "impId10111011101110111011", + "price": 2, + "adm": "{}", + "adid": "12235", + "adomain": [ + "domain.test" + ], + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/displayio/displayiotest/supplemental/unexpected-media-type.json b/adapters/displayio/displayiotest/supplemental/unexpected-media-type.json index be66747a4c..6b14653264 100644 --- a/adapters/displayio/displayiotest/supplemental/unexpected-media-type.json +++ b/adapters/displayio/displayiotest/supplemental/unexpected-media-type.json @@ -98,7 +98,7 @@ ], "expectedMakeBidsErrors": [ { - "value": "unexpected media type for bid: .*", + "value": "unsupported MType .*", "comparison": "regex" } ] diff --git a/static/bidder-info/displayio.yaml b/static/bidder-info/displayio.yaml index 4b3b28b745..6c2a04b65f 100644 --- a/static/bidder-info/displayio.yaml +++ b/static/bidder-info/displayio.yaml @@ -10,7 +10,11 @@ capabilities: mediaTypes: - banner - video + - audio + - native site: mediaTypes: - banner - - video \ No newline at end of file + - video + - audio + - native \ No newline at end of file From f5f6439fe4ff2cb5991c2e7437a97dfd7ca04d70 Mon Sep 17 00:00:00 2001 From: prebid-compas <prebid@compas-inc.com> Date: Tue, 9 Jun 2026 22:29:03 +0300 Subject: [PATCH 235/272] New Adapter: Synapse HX (#4795) --- adapters/synapseHX/params_test.go | 45 ++++ adapters/synapseHX/synapseHX.go | 147 ++++++++++ adapters/synapseHX/synapseHX_test.go | 18 ++ .../synapseHXtest/exemplary/banner.json | 167 ++++++++++++ .../synapseHXtest/exemplary/video.json | 253 ++++++++++++++++++ .../invalid-resp-empty-seatbid.json | 137 ++++++++++ .../supplemental/invalid-resp-media-type.json | 158 +++++++++++ .../supplemental/invalid-resp-mtype.json | 154 +++++++++++ .../invalid-resp-no-media-type.json | 153 +++++++++++ .../request-invalid-imp-bidder-ext.json | 55 ++++ .../supplemental/request-no-imp-ext.json | 50 ++++ .../supplemental/request-no-imp.json | 24 ++ .../supplemental/resp-invalid-no-body.json | 133 +++++++++ .../supplemental/status-204.json | 127 +++++++++ .../supplemental/status-400.json | 133 +++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_synapseHX.go | 5 + static/bidder-info/synapseHX.yaml | 21 ++ static/bidder-params/synapseHX.json | 14 + 20 files changed, 1798 insertions(+) create mode 100644 adapters/synapseHX/params_test.go create mode 100644 adapters/synapseHX/synapseHX.go create mode 100644 adapters/synapseHX/synapseHX_test.go create mode 100644 adapters/synapseHX/synapseHXtest/exemplary/banner.json create mode 100644 adapters/synapseHX/synapseHXtest/exemplary/video.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-empty-seatbid.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-media-type.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-mtype.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-no-media-type.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/request-invalid-imp-bidder-ext.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/request-no-imp-ext.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/request-no-imp.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/resp-invalid-no-body.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/status-204.json create mode 100644 adapters/synapseHX/synapseHXtest/supplemental/status-400.json create mode 100644 openrtb_ext/imp_synapseHX.go create mode 100644 static/bidder-info/synapseHX.yaml create mode 100644 static/bidder-params/synapseHX.json diff --git a/adapters/synapseHX/params_test.go b/adapters/synapseHX/params_test.go new file mode 100644 index 0000000000..b81a17f49b --- /dev/null +++ b/adapters/synapseHX/params_test.go @@ -0,0 +1,45 @@ +package synapseHX + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch json-schemas. %v", err) + } + + for _, param := range validParams { + if err := validator.Validate(openrtb_ext.BidderSynapseHX, json.RawMessage(param)); err != nil { + t.Errorf("Schema rejected valid params: %s", param) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch json-schemas. %v", err) + } + + for _, param := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderSynapseHX, json.RawMessage(param)); err == nil { + t.Errorf("Schema allowed invalid params: %s", param) + } + } +} + +var validParams = []string{ + `{"tenantId":"a"}`, + `{"tenantId":"8cd85aed-25a6-4db0-ad98-4a3af1f7601c"}`, +} + +var invalidParams = []string{ + `{}`, + `{"tenantId":1}`, + `{"tenantId":""}`, +} diff --git a/adapters/synapseHX/synapseHX.go b/adapters/synapseHX/synapseHX.go new file mode 100644 index 0000000000..2181305687 --- /dev/null +++ b/adapters/synapseHX/synapseHX.go @@ -0,0 +1,147 @@ +package synapseHX + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + + return bidder, nil +} + +func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var requests []*adapters.RequestData + + var tenantId string + + if len(request.Imp) == 0 { + return nil, []error{fmt.Errorf("request contains no impressions")} + } + + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil { + return nil, []error{fmt.Errorf("failed to unmarshal bidder ext: %w", err)} + } + + var ext openrtb_ext.ExtImpSynapseHX + if err := jsonutil.Unmarshal(bidderExt.Bidder, &ext); err != nil { + return nil, []error{fmt.Errorf("failed to unmarshal bidder parameters: %w", err)} + } + + tenantId = ext.TenantID + + requestBody, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{fmt.Errorf("failed to marshal request: %w", err)} + } + + url, _ := url.Parse(adapter.endpoint) + q := url.Query() + q.Set("pid", tenantId) + url.RawQuery = q.Encode() + + requestData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: url.String(), + Body: requestBody, + Headers: buildRequestHeaders(), + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + requests = append(requests, requestData) + + return requests, nil +} + +func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResponse); err != nil { + return nil, []error{&errortypes.BadInput{Message: fmt.Sprintf("failed to unmarshal response body: %v", err)}} + } + + if len(bidResponse.SeatBid) == 0 || len(bidResponse.SeatBid[0].Bid) == 0 { + return nil, nil + } + + var errs []error + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResponse.SeatBid[0].Bid)) + + for i := range bidResponse.SeatBid { + for j := range bidResponse.SeatBid[i].Bid { + bid := &bidResponse.SeatBid[i].Bid[j] + bidType, err := getMediaTypeForBid(bid) + + if err != nil { + errs = append(errs, err) + } else { + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + } + + return bidderResponse, errs +} + +func buildRequestHeaders() http.Header { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("X-Openrtb-Version", "2.6") + + return headers +} + +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.MType != 0 { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + default: + return "", fmt.Errorf("unsupported media type %d", bid.MType) + } + } + + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil && bidExt.Prebid != nil { + switch bidExt.Prebid.Type { + case openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo: + return bidExt.Prebid.Type, nil + default: + return "", fmt.Errorf("unsupported media type \"%s\"", bidExt.Prebid.Type) + } + } + } + + return "", fmt.Errorf("failed to parse impression \"%s\" mediatype", bid.ImpID) +} diff --git a/adapters/synapseHX/synapseHX_test.go b/adapters/synapseHX/synapseHX_test.go new file mode 100644 index 0000000000..21ea7af97c --- /dev/null +++ b/adapters/synapseHX/synapseHX_test.go @@ -0,0 +1,18 @@ +package synapseHX + +import ( + "testing" + + "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) { + bidder, buildErr := Builder(openrtb_ext.BidderSynapseHX, config.Adapter{ + Endpoint: "http://localhost:8080/bidder/"}, config.Server{}) + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + adapterstest.RunJSONBidderTest(t, "synapseHXtest", bidder) +} diff --git a/adapters/synapseHX/synapseHXtest/exemplary/banner.json b/adapters/synapseHX/synapseHXtest/exemplary/banner.json new file mode 100644 index 0000000000..586a35dbaf --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/exemplary/banner.json @@ -0,0 +1,167 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.04, + "adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>", + "adomain": [ + "example.com" + ], + "mtype": 1 + } + ], + "seat": "seat-1" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "bid-resp-id", + "bids": [ + { + "bid": { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.04, + "adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>", + "adomain": [ + "example.com" + ], + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/exemplary/video.json b/adapters/synapseHX/synapseHXtest/exemplary/video.json new file mode 100644 index 0000000000..bb4216b7c4 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/exemplary/video.json @@ -0,0 +1,253 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a" + } + }, + "instl": 1, + "bidfloor": 0.2, + "bidfloorcur": "USD", + "video": { + "api": [ + 7 + ], + "battr": [ + 16 + ], + "companiontype": [ + 1, + 2 + ], + "h": 480, + "w": 320, + "skip": 1, + "mimes": [ + "video/mp4" + ], + "minduration": 5, + "maxduration": 30, + "linearity": 1, + "protocols": [ + 2, + 3, + 5, + 6 + ], + "pos": 7, + "startdelay": 0, + "placement": 4, + "skipmin": 0, + "skipafter": 0, + "companionad": [ + { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif" + ], + "api": [ + 3, + 5, + 6 + ], + "vcm": 1 + } + ], + "delivery": [], + "maxextended": 0 + }, + "metric": [ + { + "type": "viewability", + "value": 0.97, + "vendor": "ZZZ" + } + ], + "displaymanager": "ZZZ", + "displaymanagerver": "42.42.42", + "secure": 1 + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a" + } + }, + "instl": 1, + "bidfloor": 0.2, + "bidfloorcur": "USD", + "video": { + "api": [ + 7 + ], + "battr": [ + 16 + ], + "companiontype": [ + 1, + 2 + ], + "h": 480, + "w": 320, + "skip": 1, + "mimes": [ + "video/mp4" + ], + "minduration": 5, + "maxduration": 30, + "linearity": 1, + "protocols": [ + 2, + 3, + 5, + 6 + ], + "pos": 7, + "startdelay": 0, + "placement": 4, + "companionad": [ + { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif" + ], + "api": [ + 3, + 5, + 6 + ], + "vcm": 1 + } + ] + }, + "metric": [ + { + "type": "viewability", + "value": 0.97, + "vendor": "ZZZ" + } + ], + "displaymanager": "ZZZ", + "displaymanagerver": "42.42.42", + "secure": 1 + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.03, + "adm": "<?xml version='1.0' encoding='UTF-8'?><VAST version='3.0'><Ad id='123'><InLine><AdSystem>Prebid</AdSystem><AdTitle>Sample Video Ad</AdTitle><Creatives><Creative><Linear><Duration>00:00:30</Duration><MediaFiles><MediaFile type='video/mp4' width='640' height='360' delivery='progressive'>https://advertiser.com/video.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "adomain": [ + "example.com" + ], + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "seat-1" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "id": "bid-resp-id", + "bids": [ + { + "bid": { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.03, + "adm": "<?xml version='1.0' encoding='UTF-8'?><VAST version='3.0'><Ad id='123'><InLine><AdSystem>Prebid</AdSystem><AdTitle>Sample Video Ad</AdTitle><Creatives><Creative><Linear><Duration>00:00:30</Duration><MediaFiles><MediaFile type='video/mp4' width='640' height='360' delivery='progressive'>https://advertiser.com/video.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "adomain": [ + "example.com" + ], + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-empty-seatbid.json b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-empty-seatbid.json new file mode 100644 index 0000000000..e1a55566b1 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-empty-seatbid.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-media-type.json b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-media-type.json new file mode 100644 index 0000000000..07050f4159 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-media-type.json @@ -0,0 +1,158 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.04, + "adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>", + "adomain": [ + "example.com" + ], + "ext": { + "prebid": { + "type": "audio" + } + } + } + ], + "seat": "seat-1" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [{}], + "expectedMakeBidsErrors": [ + { + "value": "unsupported media type", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-mtype.json b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-mtype.json new file mode 100644 index 0000000000..e9c9014e77 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-mtype.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.04, + "adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>", + "adomain": [ + "example.com" + ], + "mtype": 3 + } + ], + "seat": "seat-1" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [{}], + "expectedMakeBidsErrors": [ + { + "value": "unsupported media type", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-no-media-type.json b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-no-media-type.json new file mode 100644 index 0000000000..4735ccd2a7 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/invalid-resp-no-media-type.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "body": { + "id": "bid-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-item-id", + "impid": "imp-id", + "price": 0.04, + "adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>", + "adomain": [ + "example.com" + ] + } + ], + "seat": "seat-1" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [{}], + "expectedMakeBidsErrors": [ + { + "value": "failed to parse impression", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/request-invalid-imp-bidder-ext.json b/adapters/synapseHX/synapseHXtest/supplemental/request-invalid-imp-bidder-ext.json new file mode 100644 index 0000000000..382433ef83 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/request-invalid-imp-bidder-ext.json @@ -0,0 +1,55 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": 0 + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "failed to unmarshal bidder parameters", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp-ext.json b/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp-ext.json new file mode 100644 index 0000000000..dec8f4a250 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp-ext.json @@ -0,0 +1,50 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "failed to unmarshal bidder ext", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp.json b/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp.json new file mode 100644 index 0000000000..0217586de9 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/request-no-imp.json @@ -0,0 +1,24 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "request contains no impressions", + "comparison": "literal" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/resp-invalid-no-body.json b/adapters/synapseHX/synapseHXtest/supplemental/resp-invalid-no-body.json new file mode 100644 index 0000000000..5c06b5add0 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/resp-invalid-no-body.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.5" + ] + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "failed to unmarshal response body", + "comparison": "startswith" + } + ] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/status-204.json b/adapters/synapseHX/synapseHXtest/supplemental/status-204.json new file mode 100644 index 0000000000..2e2e89bcef --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/status-204.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 204, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + } + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/synapseHX/synapseHXtest/supplemental/status-400.json b/adapters/synapseHX/synapseHXtest/supplemental/status-400.json new file mode 100644 index 0000000000..85ba451867 --- /dev/null +++ b/adapters/synapseHX/synapseHXtest/supplemental/status-400.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "http://localhost:8080/bidder/?pid=a", + "body": { + "id": "auction-req-id", + "imp": [ + { + "id": "imp-id", + "ext": { + "bidder": { + "tenantId": "a", + "adUnitId": "b" + } + }, + "banner": { + "w": 320, + "h": 480, + "pos": 7, + "mimes": [ + "image/jpg", + "image/gif", + "text/html" + ], + "format": [ + { + "w": 320, + "h": 480 + } + ], + "api": [ + 5, + 7 + ], + "vcm": 1, + "id": "1" + } + } + ], + "site": { + "page": "https://example.com", + "publisher": { + "id": "publisher-id" + }, + "id": "site-id" + }, + "device": { + "ua": "Mozilla/5.0" + } + }, + "impIDs": [ + "imp-id" + ] + }, + "mockResponse": { + "status": 400, + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Openrtb-Version": [ + "2.6" + ] + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "startswith" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 91a1325e30..75a848b759 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -225,6 +225,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/sspBC" "github.com/prebid/prebid-server/v4/adapters/startio" "github.com/prebid/prebid-server/v4/adapters/stroeerCore" + "github.com/prebid/prebid-server/v4/adapters/synapseHX" "github.com/prebid/prebid-server/v4/adapters/taboola" "github.com/prebid/prebid-server/v4/adapters/tadvertising_blis" "github.com/prebid/prebid-server/v4/adapters/tappx" @@ -499,6 +500,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSspBC: sspBC.Builder, openrtb_ext.BidderStartIO: startio.Builder, openrtb_ext.BidderStroeerCore: stroeerCore.Builder, + openrtb_ext.BidderSynapseHX: synapseHX.Builder, openrtb_ext.BidderTaboola: taboola.Builder, openrtb_ext.BidderTAdvertisingBlis: tadvertising_blis.Builder, openrtb_ext.BidderTappx: tappx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 35dbf5e95f..aa725e7d1b 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -243,6 +243,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSspBC, BidderStartIO, BidderStroeerCore, + BidderSynapseHX, BidderTaboola, BidderTAdvertisingBlis, BidderTappx, @@ -621,6 +622,7 @@ const ( BidderSspBC BidderName = "sspBC" BidderStartIO BidderName = "startio" BidderStroeerCore BidderName = "stroeerCore" + BidderSynapseHX BidderName = "synapseHX" BidderTaboola BidderName = "taboola" BidderTAdvertisingBlis BidderName = "tadvertising_blis" BidderTappx BidderName = "tappx" diff --git a/openrtb_ext/imp_synapseHX.go b/openrtb_ext/imp_synapseHX.go new file mode 100644 index 0000000000..5cc209fdb5 --- /dev/null +++ b/openrtb_ext/imp_synapseHX.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpSynapseHX struct { + TenantID string `json:"tenantId"` +} diff --git a/static/bidder-info/synapseHX.yaml b/static/bidder-info/synapseHX.yaml new file mode 100644 index 0000000000..2424fd76e4 --- /dev/null +++ b/static/bidder-info/synapseHX.yaml @@ -0,0 +1,21 @@ +endpoint: "https://rtb.hx.compasonline.com/pbs" +maintainer: + email: prebid@compas-inc.com +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + redirect: + url: "https://sync.hx.compasonline.com/pbserver/image?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "${VISITOR_ID}" + iframe: + url: "https://sync.hx.compasonline.com/pbserver/iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "${VISITOR_ID}" diff --git a/static/bidder-params/synapseHX.json b/static/bidder-params/synapseHX.json new file mode 100644 index 0000000000..167a0b8f07 --- /dev/null +++ b/static/bidder-params/synapseHX.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Synapse HX Adapter Params", + "description": "A schema which validates params accepted by the Synapse HX adapter", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "description": "Synapse HX tenant identifier", + "minLength": 1 + } + }, + "required": ["tenantId"] +} From 0ef82cbb44f00b15290d02883c315e0f5a109536 Mon Sep 17 00:00:00 2001 From: Ankit Karwa <37686606+karwaankit32@users.noreply.github.com> Date: Wed, 24 Jun 2026 02:38:44 +0530 Subject: [PATCH 236/272] Upgrade Go version from 1.24 to 1.26 (#4737) Co-authored-by: Ankit Karwa <ankitkarwa@microsoft.com> Co-authored-by: Anish B <anishb@microsoft.com> --- .devcontainer/devcontainer.json | 2 +- .github/workflows/adapter-code-coverage.yml | 2 ++ .github/workflows/validate-merge.yml | 2 +- .github/workflows/validate.yml | 3 ++- Dockerfile | 4 ++-- README.md | 2 +- adapters/adapterstest/adapter_test_util.go | 6 +++--- endpoints/openrtb2/amp_auction_test.go | 2 +- exchange/bidder.go | 3 +-- go.mod | 2 +- .../devicedetection/hook_raw_auction_request.go | 3 +-- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1e17a21f4b..92c421b98c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,7 @@ "dockerfile": "Dockerfile", "args": { // Update the VARIANT arg to pick a version of Go - "VARIANT": "1.24", + "VARIANT": "1.26", // Options "INSTALL_NODE": "false", "NODE_VERSION": "lts/*" diff --git a/.github/workflows/adapter-code-coverage.yml b/.github/workflows/adapter-code-coverage.yml index a085d85ffe..5cca6cb630 100644 --- a/.github/workflows/adapter-code-coverage.yml +++ b/.github/workflows/adapter-code-coverage.yml @@ -44,6 +44,8 @@ jobs: - name: Run Coverage Tests id: run_coverage if: steps.get_directories.outputs.result != '' + env: + GOTOOLCHAIN: local run: | directories=$(echo '${{ steps.get_directories.outputs.result }}' | jq -r '.[]') go mod download diff --git a/.github/workflows/validate-merge.yml b/.github/workflows/validate-merge.yml index ca633d4746..64a611f537 100644 --- a/.github/workflows/validate-merge.yml +++ b/.github/workflows/validate-merge.yml @@ -12,7 +12,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: 1.24.0 + go-version: 1.26.2 - name: Checkout Merged Branch uses: actions/checkout@v4 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index df71d61612..b8d5ea7a55 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -10,7 +10,7 @@ jobs: validate: strategy: matrix: - go-version: [1.23.x, 1.24.x] + go-version: [1.25.x, 1.26.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} @@ -31,3 +31,4 @@ jobs: ./validate.sh --nofmt --cov --race 10 env: GO111MODULE: "on" + GOTOOLCHAIN: local diff --git a/Dockerfile b/Dockerfile index cc6a3fdf1c..4f0948351b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,8 +6,8 @@ RUN apt-get update && \ apt-get -y upgrade && \ apt-get install -y --no-install-recommends wget ca-certificates WORKDIR /tmp -RUN wget https://dl.google.com/go/go1.24.0.linux-amd64.tar.gz && \ - tar -xf go1.24.0.linux-amd64.tar.gz && \ +RUN wget https://dl.google.com/go/go1.26.2.linux-amd64.tar.gz && \ + tar -xf go1.26.2.linux-amd64.tar.gz && \ mv go /usr/local RUN mkdir -p /app/prebid-server/ WORKDIR /app/prebid-server/ diff --git a/README.md b/README.md index 0aa629ebc2..2323db2d09 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Ensure that you deploy the `/static` directory, as Prebid Server requires those ## Developing -Prebid Server requires [Go](https://go.dev) version 1.23 or newer. You can develop on any operating system that Go supports; however, please note that our helper scripts are written in bash. +Prebid Server requires [Go](https://go.dev) version 1.26.2 or newer. You can develop on any operating system that Go supports; however, please note that our helper scripts are written in bash. 1. Clone The Repository ``` bash diff --git a/adapters/adapterstest/adapter_test_util.go b/adapters/adapterstest/adapter_test_util.go index d58437b8fd..7faecb8948 100644 --- a/adapters/adapterstest/adapter_test_util.go +++ b/adapters/adapterstest/adapter_test_util.go @@ -45,21 +45,21 @@ func SampleBid(width *int64, height *int64, impId string, index int) openrtb2.Bi // VerifyStringValue Helper function to assert string equals. func VerifyStringValue(value string, expected string, t *testing.T) { if value != expected { - t.Fatalf(fmt.Sprintf("%s expected, got %s", expected, value)) + t.Fatalf("%s expected, got %s", expected, value) } } // VerifyIntValue Helper function to assert Int equals. func VerifyIntValue(value int, expected int, t *testing.T) { if value != expected { - t.Fatalf(fmt.Sprintf("%d expected, got %d", expected, value)) + t.Fatalf("%d expected, got %d", expected, value) } } // VerifyBoolValue Helper function to assert bool equals. func VerifyBoolValue(value bool, expected bool, t *testing.T) { if value != expected { - t.Fatalf(fmt.Sprintf("%v expected, got %v", expected, value)) + t.Fatalf("%v expected, got %v", expected, value) } } diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go index 44aeb23da6..cb31a2b6ed 100644 --- a/endpoints/openrtb2/amp_auction_test.go +++ b/endpoints/openrtb2/amp_auction_test.go @@ -2491,7 +2491,7 @@ func TestAmpAuctionDebugWarningsOnly(t *testing.T) { ) for _, test := range testCases { - httpReq := httptest.NewRequest("GET", fmt.Sprintf("/openrtb2/auction/amp"+test.requestURLArguments), nil) + httpReq := httptest.NewRequest("GET", "/openrtb2/auction/amp"+test.requestURLArguments, nil) test.addRequestHeaders(httpReq) recorder := httptest.NewRecorder() diff --git a/exchange/bidder.go b/exchange/bidder.go index e96fdc1a89..87d3eaa719 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -616,7 +616,7 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re httpResp, err := ctxhttp.Do(ctx, bidder.Client, httpReq) if err != nil { bidder.logHealthCheck(false) - if err == context.DeadlineExceeded { + if errors.Is(err, context.DeadlineExceeded) { err = &errortypes.Timeout{Message: err.Error()} var corebidder adapters.Bidder = bidder.Bidder // The bidder adapter normally stores an info-aware bidder (a bidder wrapper) @@ -631,7 +631,6 @@ func (bidder *BidderAdapter) doRequestImpl(ctx context.Context, req *adapters.Re // a loop of trying to report timeouts to the timeout notifications. go bidder.doTimeoutNotification(tb, req, logger) } - } return &httpCallInfo{ request: req, diff --git a/go.mod b/go.mod index f227b9b90c..fe98ea89ff 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prebid/prebid-server/v4 -go 1.23.0 +go 1.25 require ( github.com/51Degrees/device-detection-go/v4 v4.4.35 diff --git a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go index 4f5580a5c7..9492b4cb08 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go +++ b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go @@ -3,7 +3,6 @@ package devicedetection import ( - "fmt" "math" "github.com/prebid/prebid-server/v4/hooks/hookexecution" @@ -37,7 +36,7 @@ func handleAuctionRequestHook(ctx hookstage.ModuleInvocationContext, deviceDetec result, err := hydrateFields(deviceInfo, rawPayload) if err != nil { - return rawPayload, hookexecution.NewFailure(fmt.Sprintf("error hydrating fields %s", err)) + return rawPayload, hookexecution.NewFailure("error hydrating fields %s", err) } return result, nil From 16f2ebd62d506b91e328eedb6f9ea1ce33a03f68 Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:52:14 +0300 Subject: [PATCH 237/272] Attekmi: Update root domain (#4608) --- static/bidder-info/addigi.yaml | 2 +- static/bidder-info/adinify.yaml | 2 +- static/bidder-info/artechnology.yaml | 2 +- static/bidder-info/felixads.yaml | 2 +- static/bidder-info/jambojar.yaml | 2 +- static/bidder-info/jdpmedia.yaml | 2 +- static/bidder-info/markapp.yaml | 2 +- static/bidder-info/smarthub.yaml | 2 +- static/bidder-info/tredio.yaml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/static/bidder-info/addigi.yaml b/static/bidder-info/addigi.yaml index 8514d5c550..1952e5e7fd 100644 --- a/static/bidder-info/addigi.yaml +++ b/static/bidder-info/addigi.yaml @@ -1,2 +1,2 @@ -endpoint: "https://addigi-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://addigi-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" diff --git a/static/bidder-info/adinify.yaml b/static/bidder-info/adinify.yaml index 501b54df3f..9f796ac970 100644 --- a/static/bidder-info/adinify.yaml +++ b/static/bidder-info/adinify.yaml @@ -1,2 +1,2 @@ -endpoint: "https://adinify-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://adinify-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" diff --git a/static/bidder-info/artechnology.yaml b/static/bidder-info/artechnology.yaml index 0781235336..429ed3cda2 100644 --- a/static/bidder-info/artechnology.yaml +++ b/static/bidder-info/artechnology.yaml @@ -1,2 +1,2 @@ -endpoint: "https://artechnology-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://artechnology-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" diff --git a/static/bidder-info/felixads.yaml b/static/bidder-info/felixads.yaml index baa2268f4d..2068293eaa 100644 --- a/static/bidder-info/felixads.yaml +++ b/static/bidder-info/felixads.yaml @@ -1,2 +1,2 @@ -endpoint: "https://felixads-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://felixads-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" diff --git a/static/bidder-info/jambojar.yaml b/static/bidder-info/jambojar.yaml index 5ab15a47d4..794e804e17 100644 --- a/static/bidder-info/jambojar.yaml +++ b/static/bidder-info/jambojar.yaml @@ -1,2 +1,2 @@ -endpoint: "https://jambojar-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://jambojar-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" diff --git a/static/bidder-info/jdpmedia.yaml b/static/bidder-info/jdpmedia.yaml index f558955a2f..2315db74ba 100644 --- a/static/bidder-info/jdpmedia.yaml +++ b/static/bidder-info/jdpmedia.yaml @@ -1,4 +1,4 @@ -endpoint: "https://jdpmedia-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://jdpmedia-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" userSync: supports: diff --git a/static/bidder-info/markapp.yaml b/static/bidder-info/markapp.yaml index b0e7106242..a55108cbe0 100644 --- a/static/bidder-info/markapp.yaml +++ b/static/bidder-info/markapp.yaml @@ -1,4 +1,4 @@ -endpoint: "https://markapp-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://markapp-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" userSync: supports: diff --git a/static/bidder-info/smarthub.yaml b/static/bidder-info/smarthub.yaml index 43e12ae257..a0941a08e9 100644 --- a/static/bidder-info/smarthub.yaml +++ b/static/bidder-info/smarthub.yaml @@ -1,4 +1,4 @@ -endpoint: "https://prebid.attekmi.com/pbserver?partnerName={{.Host}}&seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://prebid.attekmi.co/pbserver?partnerName={{.Host}}&seat={{.AccountID}}&token={{.SourceId}}" maintainer: email: "prebid@attekmi.com" capabilities: diff --git a/static/bidder-info/tredio.yaml b/static/bidder-info/tredio.yaml index fd8ac68689..d4a4e6c5be 100644 --- a/static/bidder-info/tredio.yaml +++ b/static/bidder-info/tredio.yaml @@ -1,4 +1,4 @@ -endpoint: "https://tredio-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +endpoint: "https://tredio-prebid.attekmi.co/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" aliasOf: "smarthub" userSync: supports: From 46b9eecd89c3fa7ad63326767929e0de1fd7a80c Mon Sep 17 00:00:00 2001 From: anishb-ms <122366082+anishb-ms@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:42:40 +0530 Subject: [PATCH 238/272] Fix intermittent EID stripping for permitted bidders (#4838) --- exchange/utils.go | 8 ++- exchange/utils_test.go | 128 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/exchange/utils.go b/exchange/utils.go index 12d57d954b..ce590dd057 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -157,6 +157,7 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, reqWrapperCopy := req.CloneAndClearImpWrappers() bidRequestCopy := *req.BidRequest reqWrapperCopy.BidRequest = &bidRequestCopy + reqWrapperCopy.Imp = imps coreBidder, isRequestAlias := resolveBidder(bidder, requestAliases) @@ -848,11 +849,14 @@ func removeUnpermissionedEids(reqWrapper *openrtb_ext.RequestWrapper, bidder str return nil } + // clone User before mutating EIDs to avoid corrupting the shared pointer + userCopy := *reqWrapper.User if len(eidsAllowed) == 0 { - reqWrapper.User.EIDs = nil + userCopy.EIDs = nil } else { - reqWrapper.User.EIDs = eidsAllowed + userCopy.EIDs = eidsAllowed } + reqWrapper.User = &userCopy return nil } diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 63f1200a94..71938e102f 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -3143,10 +3143,138 @@ func TestRemoveUnpermissionedEids(t *testing.T) { User: &openrtb2.User{EIDs: test.expectedUserEids}, } + originalUser := reqWrapper.User + resultErr := removeUnpermissionedEids(&reqWrapper, bidder) assert.NoError(t, resultErr, test.description) assert.Equal(t, expectedRequest, reqWrapper.BidRequest) + + eidsRemoved := len(test.userEids) > 0 && len(test.expectedUserEids) != len(test.userEids) + if eidsRemoved { + assert.NotSame(t, originalUser, reqWrapper.User, "User must be cloned when EIDs are removed to avoid corrupting shared state") + } + }) + } +} + +// TestCleanOpenRTBRequestsEidPermissionsRaceCondition is a regression test for issue #4792. +// +// cleanOpenRTBRequests splits a single request into per-bidder requests with a +// shallow struct copy (bidRequestCopy := *req.BidRequest). Because User is a +// pointer, every per-bidder copy used to share the same *openrtb2.User, and +// removeUnpermissionedEids mutated User.EIDs in place. The result was that a +// permitted bidder could intermittently lose its EID depending on Go map +// iteration order (the order bidders are processed in the impsByBidder loop). +// +// This test runs cleanOpenRTBRequests many times so the map iteration order +// varies, and asserts the permitted bidder ALWAYS retains the EID while +// non-permitted bidders ALWAYS have it stripped. +func TestCleanOpenRTBRequestsEidPermissionsRaceCondition(t *testing.T) { + const ( + permittedBidder = "bidderA" + eidSource = "source1" + iterations = 10 + ) + permittedBidders := []string{permittedBidder} + deniedBidders := []string{"bidderB", "bidderC"} + + buildAuctionRequest := func() AuctionRequest { + bidRequest := &openrtb2.BidRequest{ + ID: "race-cond", + User: &openrtb2.User{ + EIDs: []openrtb2.EID{ + {Source: eidSource, UIDs: []openrtb2.UID{{ID: "shared-id", AType: 1}}}, + }, + }, + Imp: []openrtb2.Imp{ + { + ID: "imp-1", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Ext: json.RawMessage(`{"prebid":{"bidder":{` + + `"bidderA":{"placementId":"1"},` + + `"bidderB":{"placementId":"2"},` + + `"bidderC":{"placementId":"3"}}}}`), + }, + }, + } + + reqWrapper := &openrtb_ext.RequestWrapper{BidRequest: bidRequest} + reqExt, err := reqWrapper.GetRequestExt() + require.NoError(t, err) + reqExt.SetPrebid(&openrtb_ext.ExtRequestPrebid{ + Data: &openrtb_ext.ExtRequestPrebidData{ + EidPermissions: []openrtb_ext.ExtRequestPrebidDataEidPermission{ + {Source: eidSource, Bidders: []string{permittedBidder}}, + }, + }, }) + require.NoError(t, reqWrapper.RebuildRequest()) + + return AuctionRequest{ + BidRequestWrapper: reqWrapper, + UserSyncs: &emptyUsersync{}, + TCF2Config: gdpr.NewTCF2Config(config.TCF2{}, config.AccountGDPR{}), + } + } + + gdprPermissionsBuilder := fakePermissionsBuilder{ + permissions: &permissionsMock{ + allowAllBidders: true, + }, + }.Builder + + // Mark all bidders as ORTB 2.6 so their EIDs stay in user.eids instead of + // being down-converted into user.ext.eids, keeping the assertion simple. + bidderInfo := config.BidderInfos{ + permittedBidder: {OpenRTB: &config.OpenRTBInfo{Version: "2.6"}}, + } + for _, b := range deniedBidders { + bidderInfo[b] = config.BidderInfo{OpenRTB: &config.OpenRTBInfo{Version: "2.6"}} + } + + eidSources := func(user *openrtb2.User) []string { + if user == nil { + return nil + } + sources := make([]string, 0, len(user.EIDs)) + for _, eid := range user.EIDs { + sources = append(sources, eid.Source) + } + return sources + } + + for i := 0; i < iterations; i++ { + reqSplitter := &requestSplitter{ + bidderToSyncerKey: map[string]string{}, + me: &metrics.MetricsEngineMock{}, + privacyConfig: config.Privacy{}, + gdprPermsBuilder: gdprPermissionsBuilder, + hostSChainNode: nil, + bidderInfo: bidderInfo, + } + + bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), buildAuctionRequest(), nil, map[string]float64{}) + require.Empty(t, errs, "iteration %d returned errors", i) + require.Len(t, bidderRequests, len(permittedBidders)+len(deniedBidders), "iteration %d produced unexpected number of bidder requests", i) + + seen := make(map[string]bool, len(bidderRequests)) + for _, br := range bidderRequests { + bidder := string(br.BidderName) + seen[bidder] = true + sources := eidSources(br.BidRequest.User) + if bidder == permittedBidder { + assert.Contains(t, sources, eidSource, + "iteration %d: permitted bidder %q must retain EID %q (sources=%v)", i, bidder, eidSource, sources) + } else { + assert.NotContains(t, sources, eidSource, + "iteration %d: non-permitted bidder %q must not receive EID %q (sources=%v)", i, bidder, eidSource, sources) + } + } + + assert.True(t, seen[permittedBidder], "iteration %d: permitted bidder %q missing from results", i, permittedBidder) + for _, b := range deniedBidders { + assert.True(t, seen[b], "iteration %d: bidder %q missing from results", i, b) + } } } From 0693f77331e2b822e7542ed5c46b40052888fe72 Mon Sep 17 00:00:00 2001 From: anishb-ms <122366082+anishb-ms@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:04:59 +0530 Subject: [PATCH 239/272] Disable iFrame-based syncing for specific bidders and accounts (#4752) --- config/account.go | 17 +- config/config.go | 3 + config/config_test.go | 3 + config/usersync.go | 9 ++ endpoints/cookie_sync.go | 64 +++++++- endpoints/cookie_sync_test.go | 292 ++++++++++++++++++++++++++++++++-- usersync/bidderfilter.go | 18 +++ 7 files changed, 378 insertions(+), 28 deletions(-) diff --git a/config/account.go b/config/account.go index cc403f962b..58b699b6da 100644 --- a/config/account.go +++ b/config/account.go @@ -41,7 +41,7 @@ type Account struct { GDPR AccountGDPR `mapstructure:"gdpr" json:"gdpr"` DebugAllow bool `mapstructure:"debug_allow" json:"debug_allow"` DefaultIntegration string `mapstructure:"default_integration" json:"default_integration"` - CookieSync CookieSync `mapstructure:"cookie_sync" json:"cookie_sync"` + CookieSync AccountCookieSync `mapstructure:"cookie_sync" json:"cookie_sync"` Events Events `mapstructure:"events" json:"events"` // Don't enable this feature. It is still under developmment - https://github.com/prebid/prebid-server/issues/1725 TruncateTargetAttribute *int `mapstructure:"truncate_target_attr" json:"truncate_target_attr"` AlternateBidderCodes *openrtb_ext.ExtAlternateBidderCodes `mapstructure:"alternatebiddercodes" json:"alternatebiddercodes"` @@ -56,13 +56,14 @@ type Account struct { TargetingPrefix string `mapstructure:"targeting_prefix" json:"targeting_prefix"` } -// CookieSync represents the account-level defaults for the cookie sync endpoint. -type CookieSync struct { - DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` - MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` - DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` - PriorityGroups [][]string `mapstructure:"priority_groups" json:"priority_groups"` - PriorityGroupsOnly *bool `mapstructure:"priority_groups_only" json:"priority_groups_only"` +// AccountCookieSync represents the account-level defaults for the cookie sync endpoint. +type AccountCookieSync struct { + DefaultLimit *int `mapstructure:"default_limit" json:"default_limit"` + MaxLimit *int `mapstructure:"max_limit" json:"max_limit"` + DefaultCoopSync *bool `mapstructure:"default_coop_sync" json:"default_coop_sync"` + PriorityGroups [][]string `mapstructure:"priority_groups" json:"priority_groups"` + PriorityGroupsOnly *bool `mapstructure:"priority_groups_only" json:"priority_groups_only"` + DisabledIFrameBidders []string `mapstructure:"disabled_iframe_bidders" json:"disabled_iframe_bidders"` } // AccountCCPA represents account-specific CCPA configuration diff --git a/config/config.go b/config/config.go index ad635c199c..5d4bc86377 100644 --- a/config/config.go +++ b/config/config.go @@ -53,6 +53,9 @@ type Configuration struct { Video Video `mapstructure:"video"` Accounts StoredRequests `mapstructure:"accounts"` UserSync UserSync `mapstructure:"user_sync"` + // CookieSync holds host-level cookie sync settings that are always enforced and + // cannot be overridden by account configuration. + CookieSync CookieSync `mapstructure:"cookie_sync"` // Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives. StoredVideo StoredRequests `mapstructure:"stored_video_req"` StoredResponses StoredRequests `mapstructure:"stored_responses"` diff --git a/config/config_test.go b/config/config_test.go index 5f9cb0996f..6bb206f41f 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -431,6 +431,8 @@ ccpa: enforce: true lmt: enforce: true +cookie_sync: + disabled_iframe_bidders: ["hostBidder1", "hostBidder2"] host_cookie: cookie_name: userid family: prebid @@ -651,6 +653,7 @@ func TestFullConfig(t *testing.T) { cmpStrings(t, "cookie family", "prebid", cfg.HostCookie.Family) cmpStrings(t, "opt out", "http://prebid.org/optout", cfg.HostCookie.OptOutURL) cmpStrings(t, "opt in", "http://prebid.org/optin", cfg.HostCookie.OptInURL) + assert.Equal(t, []string{"hostBidder1", "hostBidder2"}, cfg.CookieSync.DisabledIFrameBidders, "cookie_sync.disabled_iframe_bidders") cmpStrings(t, "external url", "http://prebid-server.prebid.org/", cfg.ExternalURL) cmpStrings(t, "host", "prebid-server.prebid.org", cfg.Host) cmpInts(t, "port", 1234, cfg.Port) diff --git a/config/usersync.go b/config/usersync.go index d490853d08..7fed692cef 100644 --- a/config/usersync.go +++ b/config/usersync.go @@ -12,3 +12,12 @@ type UserSync struct { type UserSyncCooperative struct { EnabledByDefault bool `mapstructure:"default"` } + +// CookieSync specifies host-level cookie sync settings that are always enforced by the +// host operator. These settings cannot be overridden by account configuration and are +// unioned with any account-level restrictions. +type CookieSync struct { + // DisabledIFrameBidders lists bidders for which iframe cookie syncs are disabled for + // every account. Use "*" to disable iframe syncs for all bidders. + DisabledIFrameBidders []string `mapstructure:"disabled_iframe_bidders" json:"disabled_iframe_bidders"` +} diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go index 8b90cb2ff8..27ba40f0e8 100644 --- a/endpoints/cookie_sync.go +++ b/endpoints/cookie_sync.go @@ -8,6 +8,7 @@ import ( "io" "math" "net/http" + "slices" "strconv" "strings" "time" @@ -168,6 +169,9 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, ma return usersync.Request{}, macros.UserSyncPrivacy{}, account, err } + disabledIFrameBidders := mergeDisabledIFrameBidders(c.config.CookieSync.DisabledIFrameBidders, account.CookieSync.DisabledIFrameBidders) + syncTypeFilter = applyDisabledIFrameBidders(syncTypeFilter, disabledIFrameBidders) + gdprRequestInfo := gdpr.RequestInfo{ Consent: privacyMacros.GDPRConsent, GDPRSignal: gdprSignal, @@ -292,7 +296,7 @@ func (c *cookieSyncEndpoint) writeParseRequestErrorMetrics(err error) { } } -func (c *cookieSyncEndpoint) setLimit(request cookieSyncRequest, cookieSyncConfig config.CookieSync) cookieSyncRequest { +func (c *cookieSyncEndpoint) setLimit(request cookieSyncRequest, cookieSyncConfig config.AccountCookieSync) cookieSyncRequest { limit := getEffectiveLimit(request.Limit, cookieSyncConfig.DefaultLimit) maxLimit := getEffectiveMaxLimit(cookieSyncConfig.MaxLimit) if maxLimit < limit { @@ -327,7 +331,7 @@ func getEffectiveMaxLimit(maxLimit *int) int { return math.MaxInt } -func (c *cookieSyncEndpoint) setCooperativeSync(request cookieSyncRequest, cookieSyncConfig config.CookieSync) cookieSyncRequest { +func (c *cookieSyncEndpoint) setCooperativeSync(request cookieSyncRequest, cookieSyncConfig config.AccountCookieSync) cookieSyncRequest { if request.CooperativeSync == nil && cookieSyncConfig.DefaultCoopSync != nil { request.CooperativeSync = cookieSyncConfig.DefaultCoopSync } @@ -335,7 +339,7 @@ func (c *cookieSyncEndpoint) setCooperativeSync(request cookieSyncRequest, cooki return request } -func (c *cookieSyncEndpoint) findPriorityGroups(accountCookieSyncConfig config.CookieSync) [][]string { +func (c *cookieSyncEndpoint) findPriorityGroups(accountCookieSyncConfig config.AccountCookieSync) [][]string { // Account-level config takes precedence over global config, which will be deprecated in the future if accountCookieSyncConfig.DefaultCoopSync != nil { return accountCookieSyncConfig.PriorityGroups @@ -343,6 +347,60 @@ func (c *cookieSyncEndpoint) findPriorityGroups(accountCookieSyncConfig config.C return c.config.UserSync.PriorityGroups } +// mergeDisabledIFrameBidders returns the union of the host-level and account-level +// disabled iframe bidder lists. Host-level entries are always enforced and cannot be +// overridden by account configuration. Duplicates are removed while preserving order, +// with host entries taking precedence. +func mergeDisabledIFrameBidders(host, account []string) []string { + if len(host) == 0 { + return account + } + if len(account) == 0 { + return host + } + + merged := make([]string, 0, len(host)+len(account)) + seen := make(map[string]struct{}, len(host)+len(account)) + for _, bidder := range host { + if _, ok := seen[bidder]; !ok { + seen[bidder] = struct{}{} + merged = append(merged, bidder) + } + } + for _, bidder := range account { + if _, ok := seen[bidder]; !ok { + seen[bidder] = struct{}{} + merged = append(merged, bidder) + } + } + return merged +} + +// applyDisabledIFrameBidders enforces iframe cookie sync restrictions from the union of +// host-level and account-level configuration. +// The disabledIFrameBidders slice supports two formats, matching the filterSettings convention: +// - "*" (string): disables iframe syncs for all bidders +// - ["bidderA", "bidderB"] (array): disables iframe syncs for specific bidders only +// When specific bidders are disabled, a CompositeFilter ANDs the request-level filter with the +// configured filter, ensuring configuration can only further restrict — never broaden — +// what the request's filterSettings allows. Redirect syncs are never affected. +func applyDisabledIFrameBidders(syncTypeFilter usersync.SyncTypeFilter, disabledIFrameBidders []string) usersync.SyncTypeFilter { + if len(disabledIFrameBidders) == 0 { + return syncTypeFilter + } + + if slices.Contains(disabledIFrameBidders, "*") { + syncTypeFilter.IFrame = usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude) + } else { + syncTypeFilter.IFrame = usersync.CompositeFilter{ + RequestFilter: syncTypeFilter.IFrame, + AccountFilter: usersync.NewSpecificBidderFilter(disabledIFrameBidders, usersync.BidderFilterModeExclude), + } + } + + return syncTypeFilter +} + func parseTypeFilter(request *cookieSyncRequestFilterSettings) (usersync.SyncTypeFilter, error) { syncTypeFilter := usersync.SyncTypeFilter{ IFrame: cookieSyncBidderFilterAllowAll, diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index 503eb9c35b..5c022895a0 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -588,6 +588,7 @@ func TestCookieSyncParseRequest(t *testing.T) { testCases := []struct { description string givenConfig config.UserSync + givenCookieSyncConfig config.CookieSync givenBody io.Reader givenGDPRConfig config.GDPR givenCCPAEnabled bool @@ -1108,6 +1109,78 @@ func TestCookieSyncParseRequest(t *testing.T) { expectedError: errCookieSyncAccountBlocked.Error(), givenAccountRequired: true, }, + { + description: "IFrame Disabled For All Bidders Via Account Config Wildcard", + givenBody: strings.NewReader(`{` + + `"bidders":["a", "b"],` + + `"account":"IFrameDisabledAllAccount"` + + `}`), + givenGDPRConfig: config.GDPR{Enabled: true, DefaultValue: "0"}, + givenCCPAEnabled: true, + givenConfig: config.UserSync{ + PriorityGroups: [][]string{{"a", "b", "c"}}, + Cooperative: config.UserSyncCooperative{ + EnabledByDefault: false, + }, + }, + expectedPrivacy: macros.UserSyncPrivacy{}, + expectedRequest: usersync.Request{ + Bidders: []string{"a", "b"}, + Cooperative: usersync.Cooperative{ + Enabled: true, + PriorityGroups: nil, + }, + Limit: 20, + Privacy: usersyncPrivacy{ + gdprPermissions: &fakePermissions{}, + activityRequest: emptyActivityPoliciesRequest, + gdprSignal: -1, + }, + SyncTypeFilter: usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + }, + { + description: "IFrame Disabled For Specific Bidders", + givenBody: strings.NewReader(`{` + + `"bidders":["biddera", "bidderb"],` + + `"account":"IFrameDisabledAccount"` + + `}`), + givenGDPRConfig: config.GDPR{Enabled: true, DefaultValue: "0"}, + givenCCPAEnabled: true, + givenConfig: config.UserSync{ + PriorityGroups: [][]string{{"biddera", "bidderb", "bidderc"}}, + Cooperative: config.UserSyncCooperative{ + EnabledByDefault: false, + }, + }, + givenCookieSyncConfig: config.CookieSync{ + DisabledIFrameBidders: []string{"bidderb"}, + }, + expectedPrivacy: macros.UserSyncPrivacy{}, + expectedRequest: usersync.Request{ + Bidders: []string{"biddera", "bidderb"}, + Cooperative: usersync.Cooperative{ + Enabled: true, + PriorityGroups: nil, + }, + Limit: 20, + Privacy: usersyncPrivacy{ + gdprPermissions: &fakePermissions{}, + activityRequest: emptyActivityPoliciesRequest, + gdprSignal: -1, + }, + SyncTypeFilter: usersync.SyncTypeFilter{ + IFrame: usersync.CompositeFilter{ + RequestFilter: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + AccountFilter: usersync.NewSpecificBidderFilter([]string{"bidderb", "biddera"}, usersync.BidderFilterModeExclude), + }, + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + }, } for _, test := range testCases { @@ -1128,6 +1201,7 @@ func TestCookieSyncParseRequest(t *testing.T) { endpoint := cookieSyncEndpoint{ config: &config.Configuration{ UserSync: test.givenConfig, + CookieSync: test.givenCookieSyncConfig, AccountRequired: test.givenAccountRequired, }, privacyConfig: usersyncPrivacyConfig{ @@ -1139,6 +1213,8 @@ func TestCookieSyncParseRequest(t *testing.T) { accountsFetcher: FakeAccountsFetcher{AccountData: map[string]json.RawMessage{ "TestAccount": testAccountData, "DisabledAccount": json.RawMessage(`{"disabled":true}`), + "IFrameDisabledAccount": json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30, "default_coop_sync": true, "disabled_iframe_bidders": ["biddera"]}}`), + "IFrameDisabledAllAccount": json.RawMessage(`{"cookie_sync": {"default_limit": 20, "max_limit": 30, "default_coop_sync": true, "disabled_iframe_bidders": ["*"]}}`), "ValidAccountInvalidActivities": json.RawMessage(`{"privacy":{"allowactivities":{"syncUser":{"rules":[{"condition":{"componentName": ["bidderA.bidderB.bidderC"]}}]}}}}`), }}, } @@ -1306,7 +1382,7 @@ func TestSetLimit(t *testing.T) { Limit: nil, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultLimit: nil, MaxLimit: nil, }, @@ -1321,7 +1397,7 @@ func TestSetLimit(t *testing.T) { Limit: intNegative, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultLimit: int20, }, }, @@ -1335,7 +1411,7 @@ func TestSetLimit(t *testing.T) { Limit: int0, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultLimit: int20, }, }, @@ -1349,7 +1425,7 @@ func TestSetLimit(t *testing.T) { Limit: int10, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultLimit: int20, MaxLimit: int30, }, @@ -1364,7 +1440,7 @@ func TestSetLimit(t *testing.T) { Limit: int30, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultLimit: int20, MaxLimit: int10, }, @@ -1379,7 +1455,7 @@ func TestSetLimit(t *testing.T) { Limit: intMax, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{}, + CookieSync: config.AccountCookieSync{}, }, expectedRequest: cookieSyncRequest{ Limit: intMax, @@ -1412,7 +1488,7 @@ func TestSetCooperativeSync(t *testing.T) { CooperativeSync: nil, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultCoopSync: nil, }, }, @@ -1426,7 +1502,7 @@ func TestSetCooperativeSync(t *testing.T) { CooperativeSync: nil, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultCoopSync: &coopSyncTrue, }, }, @@ -1440,7 +1516,7 @@ func TestSetCooperativeSync(t *testing.T) { CooperativeSync: &coopSyncTrue, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultCoopSync: nil, }, }, @@ -1454,7 +1530,7 @@ func TestSetCooperativeSync(t *testing.T) { CooperativeSync: &coopSyncFalse, }, givenAccount: &config.Account{ - CookieSync: config.CookieSync{ + CookieSync: config.AccountCookieSync{ DefaultCoopSync: &coopSyncTrue, }, }, @@ -1537,6 +1613,188 @@ func TestCookieSyncWriteParseRequestErrorMetrics(t *testing.T) { } } +func TestMergeDisabledIFrameBidders(t *testing.T) { + testCases := map[string]struct { + givenHost []string + givenAccount []string + expected []string + }{ + "both_nil": { + givenHost: nil, + givenAccount: nil, + expected: nil, + }, + "host_only": { + givenHost: []string{"bidderA", "bidderB"}, + givenAccount: nil, + expected: []string{"bidderA", "bidderB"}, + }, + "account_only": { + givenHost: nil, + givenAccount: []string{"bidderA", "bidderB"}, + expected: []string{"bidderA", "bidderB"}, + }, + "union": { + givenHost: []string{"bidderA"}, + givenAccount: []string{"bidderB"}, + expected: []string{"bidderA", "bidderB"}, + }, + "dedupe_host_precedence": { + givenHost: []string{"bidderA", "bidderB"}, + givenAccount: []string{"bidderB", "bidderC"}, + expected: []string{"bidderA", "bidderB", "bidderC"}, + }, + "wildcard_from_host": { + givenHost: []string{"*"}, + givenAccount: []string{"bidderA"}, + expected: []string{"*", "bidderA"}, + }, + "wildcard_from_account": { + givenHost: []string{"bidderA"}, + givenAccount: []string{"*"}, + expected: []string{"bidderA", "*"}, + }, + "wildcard_not_first_in_host": { + givenHost: []string{"bidderA", "*", "bidderB"}, + givenAccount: []string{"bidderC"}, + expected: []string{"bidderA", "*", "bidderB", "bidderC"}, + }, + "wildcard_not_first_in_account": { + givenHost: []string{"bidderA"}, + givenAccount: []string{"bidderB", "*"}, + expected: []string{"bidderA", "bidderB", "*"}, + }, + "wildcard_in_both_deduped": { + givenHost: []string{"bidderA", "*"}, + givenAccount: []string{"*", "bidderB"}, + expected: []string{"bidderA", "*", "bidderB"}, + }, + } + + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + result := mergeDisabledIFrameBidders(test.givenHost, test.givenAccount) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestApplyDisabledIFrameBidders(t *testing.T) { + allowAll := usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + } + + testCases := map[string]struct { + givenFilter usersync.SyncTypeFilter + givenBidders []string + expectedIFrame map[string]bool + expectedRedirect map[string]bool + expectedExactSync *usersync.SyncTypeFilter + }{ + "nil": { + givenFilter: allowAll, + givenBidders: nil, + expectedExactSync: &usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + "empty": { + givenFilter: allowAll, + givenBidders: []string{}, + expectedExactSync: &usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + "wildcard": { + givenFilter: allowAll, + givenBidders: []string{"*"}, + expectedExactSync: &usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + "specific_bidders": { + givenFilter: allowAll, + givenBidders: []string{"bidderA", "bidderB"}, + expectedIFrame: map[string]bool{ + "biddera": false, + "bidderb": false, + "bidderc": true, + }, + expectedRedirect: map[string]bool{ + "biddera": true, + }, + }, + // wildcard in givenBidders overrides the request-level redirect filter + "wildcard_overrides_request_filter": { + givenFilter: usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + Redirect: usersync.NewSpecificBidderFilter([]string{"biddera"}, usersync.BidderFilterModeExclude), + }, + givenBidders: []string{"*"}, + expectedExactSync: &usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude), + Redirect: usersync.NewSpecificBidderFilter([]string{"biddera"}, usersync.BidderFilterModeExclude), + }, + }, + // request already excludes all iframe; account restriction still results in all blocked + "request_excludes_all": { + givenFilter: usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + givenBidders: []string{"bidderA"}, + expectedIFrame: map[string]bool{ + "biddera": false, + "bidderb": false, + }, + }, + // request includes specific bidders; account disables one of them + "request_includes_specific": { + givenFilter: usersync.SyncTypeFilter{ + IFrame: usersync.NewSpecificBidderFilter([]string{"bidderA", "bidderB"}, usersync.BidderFilterModeInclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + givenBidders: []string{"bidderA"}, + expectedIFrame: map[string]bool{ + "biddera": false, + "bidderb": true, + "bidderc": false, + }, + }, + // wildcard takes precedence when mixed with specific bidders + "wildcard_with_specific": { + givenFilter: allowAll, + givenBidders: []string{"*", "biddera"}, + expectedExactSync: &usersync.SyncTypeFilter{ + IFrame: usersync.NewUniformBidderFilter(usersync.BidderFilterModeExclude), + Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude), + }, + }, + } + + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + result := applyDisabledIFrameBidders(test.givenFilter, test.givenBidders) + + if test.expectedExactSync != nil { + assert.Equal(t, *test.expectedExactSync, result) + } + + for bidder, expected := range test.expectedIFrame { + assert.Equal(t, expected, result.IFrame.Allowed(bidder), "IFrame.Allowed(%s)", bidder) + } + + for bidder, expected := range test.expectedRedirect { + assert.Equal(t, expected, result.Redirect.Allowed(bidder), "Redirect.Allowed(%s)", bidder) + } + }) + } +} + func TestParseTypeFilter(t *testing.T) { testCases := []struct { description string @@ -2517,7 +2775,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { testCases := []struct { description string givenGlobalConfig config.UserSync - givenAccountCookieSync config.CookieSync + givenAccountCookieSync config.AccountCookieSync expectedPriorityGroups [][]string }{ { @@ -2525,7 +2783,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: ptrutil.ToPtr(true), PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, }, @@ -2536,7 +2794,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: ptrutil.ToPtr(false), PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, }, @@ -2547,7 +2805,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: nil, PriorityGroups: [][]string{{"account1", "account2"}, {"account3"}}, }, @@ -2558,7 +2816,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: ptrutil.ToPtr(true), PriorityGroups: [][]string{}, }, @@ -2569,7 +2827,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: [][]string{{"global1", "global2"}, {"global3"}}, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: ptrutil.ToPtr(true), PriorityGroups: nil, }, @@ -2580,7 +2838,7 @@ func TestCookieSyncFindPriorityGroups(t *testing.T) { givenGlobalConfig: config.UserSync{ PriorityGroups: nil, }, - givenAccountCookieSync: config.CookieSync{ + givenAccountCookieSync: config.AccountCookieSync{ DefaultCoopSync: nil, PriorityGroups: [][]string{{"account1", "account2"}}, }, diff --git a/usersync/bidderfilter.go b/usersync/bidderfilter.go index 2e4df476f2..47a7fca646 100644 --- a/usersync/bidderfilter.go +++ b/usersync/bidderfilter.go @@ -64,3 +64,21 @@ func (f UniformBidderFilter) Allowed(bidder string) bool { func NewUniformBidderFilter(mode BidderFilterMode) BidderFilter { return UniformBidderFilter{mode: mode} } + +type CompositeFilter struct { + RequestFilter BidderFilter + AccountFilter BidderFilter +} + +func (f CompositeFilter) Allowed(bidder string) bool { + if f.RequestFilter == nil && f.AccountFilter == nil { + return true + } + if f.RequestFilter == nil { + return f.AccountFilter.Allowed(bidder) + } + if f.AccountFilter == nil { + return f.RequestFilter.Allowed(bidder) + } + return f.RequestFilter.Allowed(bidder) && f.AccountFilter.Allowed(bidder) +} From a159deca8ba317e0c0cf1d542881a752fc2b2fdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:47:10 -0400 Subject: [PATCH 240/272] Bump google.golang.org/grpc from 1.56.3 to 1.79.3 (#4821) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Brian Sardo <1168933+bsardo@users.noreply.github.com> --- go.mod | 20 +++++++++---------- go.sum | 61 ++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index fe98ea89ff..608b5df757 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ require ( github.com/docker/go-units v0.4.0 github.com/go-sql-driver/mysql v1.6.0 github.com/gofrs/uuid v4.2.0+incompatible - github.com/golang/glog v1.2.4 - github.com/google/go-cmp v0.6.0 + github.com/golang/glog v1.2.5 + github.com/google/go-cmp v0.7.0 github.com/json-iterator/go v1.1.12 github.com/julienschmidt/httprouter v1.3.0 github.com/lib/pq v1.10.4 @@ -40,19 +40,19 @@ require ( github.com/vrischmann/go-metrics-influxdb v0.1.1 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yudai/gojsondiff v1.0.0 - golang.org/x/net v0.38.0 - golang.org/x/text v0.23.0 - google.golang.org/grpc v1.56.3 + golang.org/x/net v0.48.0 + golang.org/x/text v0.32.0 + google.golang.org/grpc v1.79.3 gopkg.in/evanphx/json-patch.v5 v5.9.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d // indirect github.com/magiconair/properties v1.8.6 // indirect @@ -77,10 +77,10 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yudai/pp v2.0.1+incompatible // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/sys v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/sys v0.39.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 6886cbb7b6..e015270720 100644 --- a/go.sum +++ b/go.sum @@ -86,7 +86,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -95,8 +94,8 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c h1:eXqCBUHfmjbeDqcuvzjsd+bM6A+bnwo5N9FVbV6m5/s= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c/go.mod h1:omJZNg0Qu76bxJd+ExohVo8uXzNcGOk2bv7vel460xk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -158,6 +157,10 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -169,8 +172,8 @@ github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= -github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -201,8 +204,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -220,8 +223,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -245,6 +248,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -533,6 +538,18 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -551,8 +568,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -637,8 +654,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -749,8 +766,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -763,8 +780,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -828,6 +845,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -967,8 +986,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -983,8 +1002,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From d47fe7b184f850e1c24e488f5e0b300c49870b1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:14:40 -0400 Subject: [PATCH 241/272] Bump golang.org/x/net from 0.38.0 to 0.55.0 (#4844) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bsardo <1168933+bsardo@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 608b5df757..ba698e7b09 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prebid/prebid-server/v4 -go 1.25 +go 1.25.0 require ( github.com/51Degrees/device-detection-go/v4 v4.4.35 @@ -40,8 +40,8 @@ require ( github.com/vrischmann/go-metrics-influxdb v0.1.1 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yudai/gojsondiff v1.0.0 - golang.org/x/net v0.48.0 - golang.org/x/text v0.32.0 + golang.org/x/net v0.55.0 + golang.org/x/text v0.37.0 google.golang.org/grpc v1.79.3 gopkg.in/evanphx/json-patch.v5 v5.9.0 gopkg.in/yaml.v3 v3.0.1 @@ -77,8 +77,8 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yudai/pp v2.0.1+incompatible // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/sys v0.45.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/ini.v1 v1.66.4 // indirect diff --git a/go.sum b/go.sum index e015270720..7ee7253610 100644 --- a/go.sum +++ b/go.sum @@ -568,8 +568,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -654,8 +654,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -766,8 +766,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -780,8 +780,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 940d4af61f2f9a6ac97b597069c59af650a2b11c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:55:37 -0400 Subject: [PATCH 242/272] Bump golang.org/x/crypto from 0.36.0 to 0.52.0 (#4855) Co-authored-by: Ankit Karwa <37686606+karwaankit32@users.noreply.github.com> Co-authored-by: bsardo <1168933+bsardo@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ba698e7b09..363683694e 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yudai/pp v2.0.1+incompatible // indirect - golang.org/x/crypto v0.51.0 // indirect + golang.org/x/crypto v0.52.0 // indirect golang.org/x/sys v0.45.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.36.10 // indirect diff --git a/go.sum b/go.sum index 7ee7253610..6184dea4d1 100644 --- a/go.sum +++ b/go.sum @@ -568,8 +568,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= From 0d13a08efcb92e9b2ae85366627808edd1d0e65f Mon Sep 17 00:00:00 2001 From: Pat Diggins <89027546+PBDMSFT@users.noreply.github.com> Date: Fri, 17 Jul 2026 08:46:38 -0400 Subject: [PATCH 243/272] audienceNetwork: Transform video interstitial shape and honor response currency (#4839) Co-authored-by: Pat Diggins <pdiggins+microsoft@microsoft.com> Co-authored-by: bsardo <1168933+bsardo@users.noreply.github.com> --- .../rewarded_video_interstitial.json | 138 +++++++++++++++++ ... rewarded_video_interstitial_ortb_25.json} | 2 +- .../exemplary/video-interstitial.json | 134 ++++++++++++++++ .../supplemental/bid-impid-mismatch.json | 105 +++++++++++++ .../supplemental/currency-from-response.json | 111 ++++++++++++++ .../invalid-interstitial-native.json | 2 +- ...valid-interstitial-video-non-rewarded.json | 40 ----- .../supplemental/multi-seat-mixed-bids.json | 144 ++++++++++++++++++ .../multiformat-banner-native.json | 133 ++++++++++++++++ .../multiformat-banner-video.json | 125 +++++++++++++++ ...multiformat-interstitial-banner-video.json | 140 +++++++++++++++++ ...multiformat-interstitial-video-native.json | 132 ++++++++++++++++ .../multiformat-video-native.json | 135 ++++++++++++++++ adapters/audienceNetwork/facebook.go | 105 ++++++++++--- adapters/audienceNetwork/facebook_test.go | 46 ++++++ static/bidder-info/audienceNetwork.yaml | 2 + 16 files changed, 1428 insertions(+), 66 deletions(-) create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial.json rename adapters/audienceNetwork/audienceNetworktest/exemplary/{rewarded-video-interstitial.json => rewarded_video_interstitial_ortb_25.json} (98%) create mode 100644 adapters/audienceNetwork/audienceNetworktest/exemplary/video-interstitial.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/bid-impid-mismatch.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/currency-from-response.json delete mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multi-seat-mixed-bids.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-native.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-video.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-banner-video.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-video-native.json create mode 100644 adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-video-native.json diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial.json new file mode 100644 index 0000000000..e6f5fc7d4b --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "rwdd": 1, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0, + "ext": { + "videotype": "rewarded_interstitial" + } + }, + "instl": 1, + "rwdd": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial_ortb_25.json similarity index 98% rename from adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json rename to adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial_ortb_25.json index 132df2f75f..670988dd05 100644 --- a/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded-video-interstitial.json +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/rewarded_video_interstitial_ortb_25.json @@ -67,7 +67,7 @@ "w": 0, "h": 0, "ext": { - "videotype": "rewarded" + "videotype": "rewarded_interstitial" } }, "instl": 1, diff --git a/adapters/audienceNetwork/audienceNetworktest/exemplary/video-interstitial.json b/adapters/audienceNetwork/audienceNetworktest/exemplary/video-interstitial.json new file mode 100644 index 0000000000..fc8d7ab825 --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/exemplary/video-interstitial.json @@ -0,0 +1,134 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 0, + "h": 0 + }, + "instl": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987", + "nurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "lurl": "https://www.facebook.com/audiencenetwork/nurl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}&app_version=iOS-1.0", + "burl": "https://www.facebook.com/audiencenetwork/burl/?partner=test-platform-id&app=def&placement=456&auction=123&impression=123&request=123478&bid=987&clearing_price=${AUCTION_PRICE}" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/bid-impid-mismatch.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/bid-impid-mismatch.json new file mode 100644 index 0000000000..c289f8d627 --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/bid-impid-mismatch.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [{ + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "w": -1, + "h": 250 + }, + "tagid": "123_456" + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [{ + "bid": [{ + "id": "987", + "impid": "unknown-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + }] + }], + "bidid": "654", + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [] + }], + "expectedMakeBidsErrors": [{ + "value": "bid 987 'impid' unknown-imp-id does not match any imp in the bid request", + "comparison": "literal" + }] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/currency-from-response.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/currency-from-response.json new file mode 100644 index 0000000000..17bfbfc021 --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/currency-from-response.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [{ + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "w": -1, + "h": 250 + }, + "tagid": "123_456" + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [{ + "bid": [{ + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + }] + }], + "bidid": "654", + "cur": "EUR" + } + } + }], + "expectedBidResponses": [{ + "currency": "EUR", + "bids": [{ + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "banner" + }] + }] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json index e2e88a5785..c23f0cf9c4 100644 --- a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-native.json @@ -29,7 +29,7 @@ "tmax": 500 }, "expectedMakeRequestsErrors": [{ - "value": "imp #test-imp-id: interstitial imps are only supported for banner and rewarded video", + "value": "imp #test-imp-id: interstitial imps are only supported for banner and video", "comparison": "literal" }] } diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json deleted file mode 100644 index b98ff8cbf8..0000000000 --- a/adapters/audienceNetwork/audienceNetworktest/supplemental/invalid-interstitial-video-non-rewarded.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-req-id", - "imp": [{ - "id": "test-imp-id", - "video": { - "mimes": ["video/mp4"], - "minduration": 15, - "maxduration": 30, - "protocols": [2, 3, 5, 6, 7, 8], - "linearity": 1, - "w": 940, - "h": 560 - }, - "instl": 1, - "ext": { - "bidder": { - "publisherid": "123", - "placementid": "456" - } - } - }], - "app": { - "id": "app-abc", - "bundle": "com.prebid" - }, - "device": { - "ip": "152.193.6.74" - }, - "user": { - "id": "db089de9-a62e-4861-a881-0ff15e052516", - "buyeruid": "v4_bidder_token" - }, - "tmax": 500 - }, - "expectedMakeRequestsErrors": [{ - "value": "imp #test-imp-id: interstitial imps are only supported for banner and rewarded video", - "comparison": "literal" - }] -} \ No newline at end of file diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multi-seat-mixed-bids.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multi-seat-mixed-bids.json new file mode 100644 index 0000000000..abe8e07fed --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multi-seat-mixed-bids.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": -1, + "h": 250 + }, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "invalid-bid", + "impid": "test-imp-id", + "price": 0.500000 + } + ] + }, + { + "bid": [ + { + "id": "valid-bid", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"valid-bid\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "valid-bid", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"valid-bid\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "valid-bid", + "crid": "valid-bid" + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bid invalid-bid missing 'adm'", + "comparison": "literal" + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-native.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-native.json new file mode 100644 index 0000000000..4990791d1c --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-native.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "native": { + "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "w": -1, + "h": -1 + }, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-video.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-video.json new file mode 100644 index 0000000000..f527699c6b --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-banner-video.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }], + "w": 300, + "h": 250 + }, + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [{ + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [{ + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0 + }, + "tagid": "123_456" + }], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [{ + "bid": [{ + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + }] + }], + "bidid": "654", + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":1,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "video" + }] + }] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-banner-video.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-banner-video.json new file mode 100644 index 0000000000..57f58b2a0d --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-banner-video.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 0, + "h": 0 + }, + "instl": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-video-native.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-video-native.json new file mode 100644 index 0000000000..596ce2b5cb --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-interstitial-video-native.json @@ -0,0 +1,132 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}}]}", + "ver": "1.1" + }, + "instl": 1, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 0, + "h": 0 + }, + "instl": 1, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":101,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-video-native.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-video-native.json new file mode 100644 index 0000000000..c652bb4edb --- /dev/null +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/multiformat-video-native.json @@ -0,0 +1,135 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 940, + "h": 560 + }, + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherid": "123", + "placementid": "456" + } + } + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid" + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "https://an.facebook.com/placementbid.ortb", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "X-Fb-Pool-Routing-Token": [ + "v4_bidder_token" + ] + }, + "body": { + "id": "test-imp-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 15, + "maxduration": 30, + "protocols": [2, 3, 5, 6, 7, 8], + "linearity": 1, + "w": 0, + "h": 0 + }, + "tagid": "123_456" + } + ], + "app": { + "id": "app-abc", + "bundle": "com.prebid", + "publisher": { + "id": "123" + } + }, + "device": { + "ip": "152.193.6.74" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "v4_bidder_token" + }, + "tmax": 500, + "ext": { + "authentication_id": "4e24a2b23fbfb5e41a9093b921d6cddf497c24dd5f63879038cec2ab2f27d174", + "platformid": "test-platform-id" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-imp-id", + "seatbid": [ + { + "bid": [ + { + "id": "987", + "impid": "test-imp-id", + "price": 1.000000, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":7,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}" + } + ] + } + ], + "bidid": "654", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "987", + "impid": "test-imp-id", + "price": 1, + "adm": "{\"type\":\"ID\",\"bid_id\":\"987\",\"placement_id\":\"123_456\",\"resolved_placement_id\":\"123_456\",\"sdk_version\":\"5.5.0\",\"device_id\":\"abc\",\"template\":7,\"payload\":null,\"bid_time_token\":\"v4_bidder_token=\"}", + "adid": "987", + "crid": "987" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/audienceNetwork/facebook.go b/adapters/audienceNetwork/facebook.go index 4583881b01..2e48e34472 100644 --- a/adapters/audienceNetwork/facebook.go +++ b/adapters/audienceNetwork/facebook.go @@ -169,7 +169,14 @@ func (a *adapter) modifyRequest(out *openrtb2.BidRequest) error { } else { extMap = make(map[string]interface{}) } - extMap["videotype"] = "rewarded" + // Derive videotype from standard OpenRTB signals. Meta documents + // "rewarded" and "rewarded_interstitial" as distinct rewarded videotypes. + // Use instl to distinguish: rwdd+instl → rewarded_interstitial, rwdd alone → rewarded. + if imp.Instl == 1 { + extMap["videotype"] = "rewarded_interstitial" + } else { + extMap["videotype"] = "rewarded" + } videoCopy.Ext, err = jsonutil.Marshal(extMap) if err != nil { return err @@ -196,12 +203,38 @@ func (a *adapter) modifyRequest(out *openrtb2.BidRequest) error { func modifyImp(out *openrtb2.Imp) error { impType := resolveImpType(out) - if out.Instl == 1 && !isValidInterstitial(impType, out.Rwdd) { + if out.Instl == 1 && !isValidInterstitial(impType) { return &errortypes.BadInput{ - Message: fmt.Sprintf("imp #%s: interstitial imps are only supported for banner and rewarded video", out.ID), + Message: fmt.Sprintf("imp #%s: interstitial imps are only supported for banner and video", out.ID), } } + // Meta's only non-rewarded interstitial request shape is banner{0,0}+instl:1, which + // renders display or video client-side (per Meta's Audience Network server-to-server + // spec). Map a non-rewarded video interstitial to that shape instead of rejecting it. + // Rewarded video interstitials keep their video imp so Meta receives videotype "rewarded_interstitial". + if out.Instl == 1 && impType == openrtb_ext.BidTypeVideo && out.Rwdd != 1 { + out.Banner = &openrtb2.Banner{} + impType = openrtb_ext.BidTypeBanner + } + + // Audience Network placements are single-format, so send Meta only the resolved + // media object and drop any other media carried by a multi-format impression. + switch impType { + case openrtb_ext.BidTypeBanner: + out.Video = nil + out.Audio = nil + out.Native = nil + case openrtb_ext.BidTypeVideo: + out.Banner = nil + out.Audio = nil + out.Native = nil + case openrtb_ext.BidTypeNative: + out.Banner = nil + out.Video = nil + out.Audio = nil + } + if impType == openrtb_ext.BidTypeBanner { bannerCopy := *out.Banner out.Banner = &bannerCopy @@ -241,16 +274,8 @@ func modifyImp(out *openrtb2.Imp) error { return nil } -func isValidInterstitial(impType openrtb_ext.BidType, rwdd int8) bool { - if impType == openrtb_ext.BidTypeBanner { - return true - } - - if impType == openrtb_ext.BidTypeVideo && rwdd == 1 { - return true - } - - return false +func isValidInterstitial(impType openrtb_ext.BidType) bool { + return impType == openrtb_ext.BidTypeBanner || impType == openrtb_ext.BidTypeVideo } func extractPlacementAndPublisher(out *openrtb2.Imp) (string, string, error) { @@ -341,7 +366,7 @@ func modifyImpCustom(jsonData []byte, imp *openrtb2.Imp) ([]byte, error) { case openrtb_ext.BidTypeNative: nativeMap, ok := maputil.ReadEmbeddedMap(impMap, "native") if !ok { - return jsonData, errors.New("unable to find imp[0].video in json data") + return jsonData, errors.New("unable to find imp[0].native in json data") } // Set w/h to -1 for native impressions based on the facebook native spec. @@ -382,6 +407,9 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, adapterRequest *adapter } out := adapters.NewBidderResponseWithBidsCapacity(4) + if bidResp.Cur != "" { + out.Currency = bidResp.Cur + } var errs []error for _, seatbid := range bidResp.SeatBid { @@ -413,9 +441,15 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, adapterRequest *adapter bid.AdID = obj.BidID bid.CrID = obj.BidID + bidType, err := resolveBidType(&bid, request) + if err != nil { + errs = append(errs, err) + continue + } + out.Bids = append(out.Bids, &adapters.TypedBid{ Bid: &bid, - BidType: resolveBidType(&bid, request), + BidType: bidType, }) } } @@ -423,33 +457,56 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, adapterRequest *adapter return out, errs } -func resolveBidType(bid *openrtb2.Bid, req *openrtb2.BidRequest) openrtb_ext.BidType { +// resolveBidType reports a bid's media type from the ORIGINAL request imp it fills, +// not from the Meta-facing transformed copy. This is deliberate: a non-rewarded +// video interstitial is sent to Meta as banner{0,0}+instl (see modifyImp), but the +// bid still fills the publisher's video interstitial slot, so it is reported as +// video. Meta's interstitial creative is a deferred token whose display-vs-video +// form is resolved client-side at render — the bid carries no media type — so the +// slot type is the most specific media classification the adapter can assert, and +// bid.MType is intentionally left unset rather than claiming an unverifiable form. +func resolveBidType(bid *openrtb2.Bid, req *openrtb2.BidRequest) (openrtb_ext.BidType, error) { for _, imp := range req.Imp { if bid.ImpID == imp.ID { - return resolveImpType(&imp) + return resolveImpType(&imp), nil } } - panic(fmt.Sprintf("Invalid bid imp ID %s does not match any imp IDs from the original bid request", bid.ImpID)) + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("bid %s 'impid' %s does not match any imp in the bid request", bid.ID, bid.ImpID), + } } func resolveImpType(imp *openrtb2.Imp) openrtb_ext.BidType { - if imp.Banner != nil { - return openrtb_ext.BidTypeBanner + // Preserve interstitial semantics before applying the general expected-yield + // priority. Meta accepts banner and video interstitials, but not native or audio. + if imp.Instl == 1 { + if imp.Video != nil { + return openrtb_ext.BidTypeVideo + } + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } } + // Audience Network placements are single-format. For an ordinary multi-format + // impression, prefer the formats with the highest likely yield. if imp.Video != nil { return openrtb_ext.BidTypeVideo } - if imp.Audio != nil { - return openrtb_ext.BidTypeAudio - } - if imp.Native != nil { return openrtb_ext.BidTypeNative } + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } + + if imp.Audio != nil { + return openrtb_ext.BidTypeAudio + } + // Required to satisfy compiler. Not reachable in practice due to validations performed in PBS-Core. return openrtb_ext.BidTypeBanner } diff --git a/adapters/audienceNetwork/facebook_test.go b/adapters/audienceNetwork/facebook_test.go index a9740bb57c..ed1a1866fa 100644 --- a/adapters/audienceNetwork/facebook_test.go +++ b/adapters/audienceNetwork/facebook_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v4/adapters" "github.com/prebid/prebid-server/v4/adapters/adapterstest" "github.com/prebid/prebid-server/v4/config" @@ -55,6 +56,51 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "audienceNetworktest", bidder) } +func TestResolveImpTypePriority(t *testing.T) { + tests := []struct { + name string + imp openrtb2.Imp + expected openrtb_ext.BidType + }{ + { + name: "video over banner", + imp: openrtb2.Imp{Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}}, + expected: openrtb_ext.BidTypeVideo, + }, + { + name: "native over banner", + imp: openrtb2.Imp{Banner: &openrtb2.Banner{}, Native: &openrtb2.Native{}}, + expected: openrtb_ext.BidTypeNative, + }, + { + name: "video over native and banner", + imp: openrtb2.Imp{Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}, Native: &openrtb2.Native{}}, + expected: openrtb_ext.BidTypeVideo, + }, + { + name: "interstitial banner over unsupported native", + imp: openrtb2.Imp{Banner: &openrtb2.Banner{}, Native: &openrtb2.Native{}, Instl: 1}, + expected: openrtb_ext.BidTypeBanner, + }, + { + name: "interstitial video over native", + imp: openrtb2.Imp{Video: &openrtb2.Video{}, Native: &openrtb2.Native{}, Instl: 1}, + expected: openrtb_ext.BidTypeVideo, + }, + { + name: "banner over unsupported audio", + imp: openrtb2.Imp{Banner: &openrtb2.Banner{}, Audio: &openrtb2.Audio{}}, + expected: openrtb_ext.BidTypeBanner, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, resolveImpType(&test.imp)) + }) + } +} + func TestMakeTimeoutNoticeApp(t *testing.T) { req := adapters.RequestData{ Body: []byte(`{"id":"1234","imp":[{"id":"1234"}],"app":{"publisher":{"id":"5678"}}}`), diff --git a/static/bidder-info/audienceNetwork.yaml b/static/bidder-info/audienceNetwork.yaml index 10117ce708..eb41ca9c5e 100644 --- a/static/bidder-info/audienceNetwork.yaml +++ b/static/bidder-info/audienceNetwork.yaml @@ -2,6 +2,8 @@ endpoint: "https://an.facebook.com/placementbid.ortb" disabled: true maintainer: email: "none" +openrtb: + multiformat-supported: true capabilities: app: mediaTypes: From 643268cac948fc198c901414b981c4a836f540d4 Mon Sep 17 00:00:00 2001 From: Chris Huie <3444727+ChrisHuie@users.noreply.github.com> Date: Sun, 19 Jul 2026 20:51:57 -0600 Subject: [PATCH 244/272] New Adapter: Teal (#4765) --- adapters/teal/params_test.go | 54 +++ adapters/teal/teal.go | 363 ++++++++++++++++++ adapters/teal/teal_test.go | 282 ++++++++++++++ .../exemplary/app-publisher-rewrite.json | 133 +++++++ .../exemplary/existing-request-ext.json | 135 +++++++ .../exemplary/multi-format-imp-mtype.json | 173 +++++++++ .../tealtest/exemplary/multi-format-imp.json | 131 +++++++ .../exemplary/multi-imp-same-account.json | 181 +++++++++ .../teal/tealtest/exemplary/native-imp.json | 81 ++++ .../tealtest/exemplary/placement-absent.json | 114 ++++++ .../preserves-existing-imp-ext-prebid.json | 131 +++++++ .../tealtest/exemplary/simple-banner.json | 171 +++++++++ .../tealtest/exemplary/site-no-publisher.json | 89 +++++ .../teal/tealtest/exemplary/video-imp.json | 121 ++++++ .../bid-unmatched-imp-skipped.json | 134 +++++++ .../supplemental/both-site-and-app.json | 135 +++++++ .../tealtest/supplemental/empty-seatbid.json | 83 ++++ .../tealtest/supplemental/malformed-body.json | 120 ++++++ .../mixed-imp-partial-failure.json | 156 ++++++++ .../multi-imp-divergent-account-rejected.json | 144 +++++++ .../tealtest/supplemental/multi-seatbid.json | 194 ++++++++++ .../supplemental/no-response-body.json | 119 ++++++ .../tealtest/supplemental/no-site-no-app.json | 105 +++++ .../tealtest/supplemental/status-204.json | 114 ++++++ .../tealtest/supplemental/status-400.json | 120 ++++++ .../tealtest/supplemental/status-404.json | 120 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_teal.go | 17 + static/bidder-info/teal.yaml | 27 ++ static/bidder-params/teal.json | 21 + 31 files changed, 3772 insertions(+) create mode 100644 adapters/teal/params_test.go create mode 100644 adapters/teal/teal.go create mode 100644 adapters/teal/teal_test.go create mode 100644 adapters/teal/tealtest/exemplary/app-publisher-rewrite.json create mode 100644 adapters/teal/tealtest/exemplary/existing-request-ext.json create mode 100644 adapters/teal/tealtest/exemplary/multi-format-imp-mtype.json create mode 100644 adapters/teal/tealtest/exemplary/multi-format-imp.json create mode 100644 adapters/teal/tealtest/exemplary/multi-imp-same-account.json create mode 100644 adapters/teal/tealtest/exemplary/native-imp.json create mode 100644 adapters/teal/tealtest/exemplary/placement-absent.json create mode 100644 adapters/teal/tealtest/exemplary/preserves-existing-imp-ext-prebid.json create mode 100644 adapters/teal/tealtest/exemplary/simple-banner.json create mode 100644 adapters/teal/tealtest/exemplary/site-no-publisher.json create mode 100644 adapters/teal/tealtest/exemplary/video-imp.json create mode 100644 adapters/teal/tealtest/supplemental/bid-unmatched-imp-skipped.json create mode 100644 adapters/teal/tealtest/supplemental/both-site-and-app.json create mode 100644 adapters/teal/tealtest/supplemental/empty-seatbid.json create mode 100644 adapters/teal/tealtest/supplemental/malformed-body.json create mode 100644 adapters/teal/tealtest/supplemental/mixed-imp-partial-failure.json create mode 100644 adapters/teal/tealtest/supplemental/multi-imp-divergent-account-rejected.json create mode 100644 adapters/teal/tealtest/supplemental/multi-seatbid.json create mode 100644 adapters/teal/tealtest/supplemental/no-response-body.json create mode 100644 adapters/teal/tealtest/supplemental/no-site-no-app.json create mode 100644 adapters/teal/tealtest/supplemental/status-204.json create mode 100644 adapters/teal/tealtest/supplemental/status-400.json create mode 100644 adapters/teal/tealtest/supplemental/status-404.json create mode 100644 openrtb_ext/imp_teal.go create mode 100644 static/bidder-info/teal.yaml create mode 100644 static/bidder-params/teal.json diff --git a/adapters/teal/params_test.go b/adapters/teal/params_test.go new file mode 100644 index 0000000000..34507b8967 --- /dev/null +++ b/adapters/teal/params_test.go @@ -0,0 +1,54 @@ +package teal + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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.BidderTeal, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected valid 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.BidderTeal, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed invalid params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"account":"abc"}`, + `{"account":"abc","placement":"def"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"placement":"def"}`, + `{"account":123}`, + `{"account":""}`, + `{"account":"abc","placement":42}`, + `{"account":"abc","placement":""}`, +} diff --git a/adapters/teal/teal.go b/adapters/teal/teal.go new file mode 100644 index 0000000000..d46c5ab2ec --- /dev/null +++ b/adapters/teal/teal.go @@ -0,0 +1,363 @@ +package teal + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +const ( + msgAccountValidation = "account parameter failed validation" + msgPlacementValidation = "placement parameter failed validation" + msgImpExtParseFmt = "Error parsing imp.ext for impression %s" + msgImpExtBidderParseFmt = "Error parsing imp.ext.bidder for impression %s" + msgMixedAccountFmt = "mixed-account requests are not supported: imp %q account %q differs from request account %q" +) + +// adapter is the Teal openrtb2 bidder. +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the Teal adapter for the given bidder with +// the given config. +func Builder(_ openrtb_ext.BidderName, cfg config.Adapter, _ config.Server) (adapters.Bidder, error) { + return &adapter{endpoint: cfg.Endpoint}, nil +} + +// MakeRequests transforms the openrtb2.BidRequest into a single Teal-bound HTTP +// request body: +// +// 1. Each imp's bidder-slot is decoded into ExtImpTeal and validated for +// non-blank account and (when present) non-blank placement. +// 2. Failed imps are dropped; their parse / validation errors are collected. +// 3. The first surviving imp's account is propagated to Site.Publisher.ID and +// App.Publisher.ID. Later imps must use that same account; an imp with a +// divergent account is rejected (BadInput) and dropped. +// 4. Each surviving imp gets imp.ext.prebid.storedrequest.id = placement when +// placement is set. +// 5. Request.Ext.bids is stamped with {"pbs": 1}. +// +// If no imp survives validation, returns (nil, errs) without dispatching. +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if len(request.Imp) == 0 { + return nil, nil + } + + modifiedImps := make([]openrtb2.Imp, 0, len(request.Imp)) + var errs []error + var account string + + for i := range request.Imp { + imp := request.Imp[i] + ext, err := parseImpExt(&imp) + if err != nil { + errs = append(errs, &errortypes.BadInput{Message: err.Error()}) + continue + } + if err := validateImpExt(ext); err != nil { + errs = append(errs, &errortypes.BadInput{Message: err.Error()}) + continue + } + + // All imps in a request must agree on account, which drives the single + // request-level publisher.id. The first valid imp establishes it; a later + // imp with a different account is rejected and dropped. + if account == "" { + account = ext.Account + } else if ext.Account != account { + errs = append(errs, &errortypes.BadInput{ + Message: fmt.Sprintf(msgMixedAccountFmt, imp.ID, ext.Account, account), + }) + continue + } + + modified, err := modifyImp(&imp, ext.Placement) + if err != nil { + errs = append(errs, &errortypes.BadInput{Message: err.Error()}) + continue + } + modifiedImps = append(modifiedImps, *modified) + } + + if len(modifiedImps) == 0 { + return nil, errs + } + + modifiedRequest, err := modifyBidRequest(request, account, modifiedImps) + if err != nil { + return nil, append(errs, err) + } + + body, err := jsonutil.Marshal(modifiedRequest) + if err != nil { + return nil, append(errs, err) + } + + return []*adapters.RequestData{{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: body, + Headers: standardHeaders(), + ImpIDs: openrtb_ext.GetImpIDs(modifiedRequest.Imp), + }}, errs +} + +// parseImpExt decodes imp.ext.bidder into ExtImpTeal. +func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTeal, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, fmt.Errorf(msgImpExtParseFmt, imp.ID) + } + var ext openrtb_ext.ExtImpTeal + if err := jsonutil.Unmarshal(bidderExt.Bidder, &ext); err != nil { + return nil, fmt.Errorf(msgImpExtBidderParseFmt, imp.ID) + } + return &ext, nil +} + +// validateImpExt requires a non-blank account and, when placement is present +// (non-nil), a non-blank placement. Absent placement is allowed. +func validateImpExt(ext *openrtb_ext.ExtImpTeal) error { + if isBlank(ext.Account) { + return errors.New(msgAccountValidation) + } + if ext.Placement != nil && isBlank(*ext.Placement) { + return errors.New(msgPlacementValidation) + } + return nil +} + +// isBlank reports whether s is empty or contains only whitespace. +func isBlank(s string) bool { + return strings.TrimSpace(s) == "" +} + +// modifyImp returns a copy of imp with imp.ext.prebid.storedrequest.id set to +// *placement. Returns the imp unchanged when placement is nil. Existing +// prebid or storedrequest sub-keys that are not JSON objects are tolerated by +// replacing them with fresh objects. +func modifyImp(imp *openrtb2.Imp, placement *string) (*openrtb2.Imp, error) { + if placement == nil { + return imp, nil + } + + ext, err := decodeJSONObject(imp.Ext) + if err != nil { + return nil, fmt.Errorf(msgImpExtParseFmt, imp.ID) + } + + prebid := decodeOrEmptyObject(ext["prebid"]) + storedRequest := decodeOrEmptyObject(prebid["storedrequest"]) + + placementJSON, err := jsonutil.Marshal(*placement) + if err != nil { + return nil, err + } + storedRequest["id"] = placementJSON + + storedRequestJSON, err := jsonutil.Marshal(storedRequest) + if err != nil { + return nil, err + } + prebid["storedrequest"] = storedRequestJSON + + prebidJSON, err := jsonutil.Marshal(prebid) + if err != nil { + return nil, err + } + ext["prebid"] = prebidJSON + + extJSON, err := jsonutil.Marshal(ext) + if err != nil { + return nil, err + } + + modified := *imp + modified.Ext = extJSON + return &modified, nil +} + +// decodeOrEmptyObject decodes raw as a JSON object map. Returns an empty map +// when raw is absent / "null" / not a JSON object. The returned map is NEVER +// nil — it is always safe to assign into. +func decodeOrEmptyObject(raw json.RawMessage) map[string]json.RawMessage { + out, _ := decodeJSONObject(raw) + return out +} + +// decodeJSONObject decodes raw into a JSON object map. Treats absent input +// AND the JSON literal `null` as "empty object". Returns the parse error +// untouched on invalid JSON or non-object root types so callers can surface a +// meaningful failure. The returned map is NEVER nil, even on error — callers +// can safely assign into it. +func decodeJSONObject(raw json.RawMessage) (map[string]json.RawMessage, error) { + if len(raw) == 0 { + return make(map[string]json.RawMessage), nil + } + var parsed map[string]json.RawMessage + if err := jsonutil.Unmarshal(raw, &parsed); err != nil { + return make(map[string]json.RawMessage), err + } + if parsed == nil { + return make(map[string]json.RawMessage), nil + } + return parsed, nil +} + +// modifyBidRequest applies the request-level mutations: +// +// - Site.Publisher.ID is overwritten with account when site is non-nil +// - App.Publisher.ID is overwritten with account when app is non-nil +// - Request.Ext.bids is stamped with {"pbs":1} +// +// Returns a value-copy with mutated fields; the caller's request is untouched. +func modifyBidRequest(request *openrtb2.BidRequest, account string, modifiedImps []openrtb2.Imp) (*openrtb2.BidRequest, error) { + modified := *request + modified.Imp = modifiedImps + + if request.Site != nil { + site := *request.Site + site.Publisher = clonePublisherWithID(site.Publisher, account) + modified.Site = &site + } + if request.App != nil { + app := *request.App + app.Publisher = clonePublisherWithID(app.Publisher, account) + modified.App = &app + } + + extJSON, err := mergeBidsPBSFlag(request.Ext) + if err != nil { + return nil, err + } + modified.Ext = extJSON + return &modified, nil +} + +// clonePublisherWithID returns a copy of publisher with ID overwritten, +// creating a fresh Publisher when publisher is nil. +func clonePublisherWithID(publisher *openrtb2.Publisher, id string) *openrtb2.Publisher { + if publisher == nil { + return &openrtb2.Publisher{ID: id} + } + pub := *publisher + pub.ID = id + return &pub +} + +// mergeBidsPBSFlag returns existingExt with the "bids" property set to +// {"pbs":1}; other ext fields are preserved. The "pbs":1 marker is a Teal-side +// reporting/billing signal — it tells Teal's exchange the request is being +// routed via prebid-server, distinguishing it from direct integrations. +func mergeBidsPBSFlag(existingExt json.RawMessage) (json.RawMessage, error) { + ext, err := decodeJSONObject(existingExt) + if err != nil { + return nil, fmt.Errorf("teal: failed parsing request.ext: %w", err) + } + // Overwrite any caller-provided ext.bids: the {"pbs":1} marker must be + // authoritative for Teal's reporting/billing pipeline, so a value set by the + // publisher or upstream middleware is intentionally replaced, not merged. + ext["bids"] = json.RawMessage(`{"pbs":1}`) + return jsonutil.Marshal(ext) +} + +// MakeBids parses the Teal bid response body and packages the bids into a +// BidderResponse. Status handling follows the canonical adapters helpers: +// 204 → no-content shortcut, 4xx/5xx → BadServerResponse, 200 → parse body. +// Bids whose media type cannot be resolved from the matching imp are skipped +// and their error collected, rather than silently mis-typed as banner. +func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var bidResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &bidResponse); err != nil { + return nil, []error{&errortypes.BadServerResponse{Message: err.Error()}} + } + + impsByID := make(map[string]openrtb2.Imp, len(request.Imp)) + for _, imp := range request.Imp { + impsByID[imp.ID] = imp + } + + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if bidResponse.Cur != "" { + bidderResponse.Currency = bidResponse.Cur + } + var errs []error + for _, seatBid := range bidResponse.SeatBid { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + bidType, err := getBidType(bid, impsByID) + if err != nil { + errs = append(errs, err) + continue + } + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + return bidderResponse, errs +} + +// getBidType resolves the bid's media type. Teal declares multiformat-supported, +// so a single impression can carry more than one media type (e.g. banner+video); +// introspecting the imp alone cannot disambiguate which format a given bid is for. +// The authoritative signal is the response's own bid.mtype (OpenRTB 2.6), so it is +// consulted first. +// +// Only when the response omits mtype does getBidType fall back to introspecting the +// matching impression, looked up by ID via impsByID (built once in MakeBids to avoid +// a per-bid scan of request.Imp), in banner > video > native order. Audio is omitted +// because it is not in Teal's declared capabilities. +// +// When neither the bid's mtype nor a matching imp yields a recognized media type, +// getBidType returns an error so MakeBids can skip the bid and surface the problem in +// logs rather than silently mis-typing it. +func getBidType(bid *openrtb2.Bid, impsByID map[string]openrtb2.Imp) (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 + } + if imp, ok := impsByID[bid.ImpID]; ok { + switch { + case imp.Banner != nil: + return openrtb_ext.BidTypeBanner, nil + case imp.Video != nil: + return openrtb_ext.BidTypeVideo, nil + case imp.Native != nil: + return openrtb_ext.BidTypeNative, nil + } + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("failed to determine bid type for imp %q", bid.ImpID), + } +} + +// standardHeaders returns the headers Teal expects on every outbound request. +func standardHeaders() http.Header { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return headers +} diff --git a/adapters/teal/teal_test.go b/adapters/teal/teal_test.go new file mode 100644 index 0000000000..7ca4ced1d5 --- /dev/null +++ b/adapters/teal/teal_test.go @@ -0,0 +1,282 @@ +package teal + +import ( + "encoding/json" + "errors" + "net/http" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + testEndpoint = "https://test.example.com/bid" + testAccount = "test-account" + testRequestID = "test-request-banner" +) + +// End-to-end MakeRequests/MakeBids behavior is exercised by the JSON fixtures +// under tealtest/exemplary and tealtest/supplemental. The Go tests below cover +// only what fixtures cannot: the Go error-TYPE contract (BadInput vs +// BadServerResponse), short-circuit edges, and error branches of unexported +// helpers that are unreachable through MakeRequests. + +func TestJsonSamples(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderTeal, config.Adapter{Endpoint: testEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + require.NoError(t, err, "Builder returned unexpected error") + adapterstest.RunJSONBidderTest(t, "tealtest", bidder) +} + +// TestErrorClassification pins the error-type contract, which the JSON fixtures +// cannot verify (they compare error messages only): MakeRequests parse / +// validation / account-divergence errors are *errortypes.BadInput; MakeBids +// transport errors are BadInput for 4xx and *errortypes.BadServerResponse for +// 5xx and unparseable bodies. +func TestErrorClassification(t *testing.T) { + bidder := newTealBidder(t) + + t.Run("imp.ext parse error is BadInput", func(t *testing.T) { + imp := openrtb2.Imp{ + ID: "impId", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Ext: json.RawMessage(`[]`), + } + requests, errs := bidder.MakeRequests(givenBidRequest(imp), &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + assert.Contains(t, errs[0].Error(), "Error parsing imp.ext for impression impId") + }) + + t.Run("imp.ext bidder field malformed is BadInput", func(t *testing.T) { + imp := givenBannerImp("impId", json.RawMessage(`{"bidder":[]}`)) + requests, errs := bidder.MakeRequests(givenBidRequest(imp), &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + assert.Contains(t, errs[0].Error(), "Error parsing imp.ext.bidder for impression impId") + }) + + t.Run("blank account is BadInput", func(t *testing.T) { + imp := givenBannerImp("imp1", givenImpExt(t, " ", strPtr("p"))) + requests, errs := bidder.MakeRequests(givenBidRequest(imp), &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + assert.Equal(t, msgAccountValidation, errs[0].Error()) + }) + + t.Run("blank placement is BadInput", func(t *testing.T) { + imp := givenBannerImp("imp1", givenImpExt(t, "acct", strPtr(" "))) + requests, errs := bidder.MakeRequests(givenBidRequest(imp), &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + assert.Equal(t, msgPlacementValidation, errs[0].Error()) + }) + + t.Run("divergent account is BadInput", func(t *testing.T) { + first := givenBannerImp("imp1", givenImpExt(t, "acct-a", strPtr("p1"))) + second := givenBannerImp("imp2", givenImpExt(t, "acct-b", strPtr("p2"))) + requests, errs := bidder.MakeRequests(givenBidRequest(first, second), &adapters.ExtraRequestInfo{}) + require.Len(t, requests, 1, "first imp still ships") + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + assert.Contains(t, errs[0].Error(), "mixed-account requests are not supported") + }) + + t.Run("malformed request.ext propagates parse error", func(t *testing.T) { + imp := givenBannerImp("imp1", givenImpExt(t, testAccount, nil)) + req := givenBidRequest(imp) + req.Ext = json.RawMessage(`{"prebid":}`) // syntactically invalid + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + require.NotEmpty(t, errs) + assert.Contains(t, errs[len(errs)-1].Error(), "failed parsing request.ext") + }) + + t.Run("MakeBids 4xx is BadInput", func(t *testing.T) { + resp, errs := makeBidsCall(t, bidder, &openrtb2.BidRequest{}, http.StatusBadRequest, []byte(`{}`)) + assert.Nil(t, resp) + require.Len(t, errs, 1) + assert.True(t, isBadInputErr(errs[0]), "got %T", errs[0]) + }) + + t.Run("MakeBids 5xx is BadServerResponse", func(t *testing.T) { + resp, errs := makeBidsCall(t, bidder, &openrtb2.BidRequest{}, http.StatusInternalServerError, []byte(`{}`)) + assert.Nil(t, resp) + require.Len(t, errs, 1) + assert.True(t, isBadServerErr(errs[0]), "got %T", errs[0]) + }) + + t.Run("MakeBids unparseable body is BadServerResponse", func(t *testing.T) { + resp, errs := makeBidsCall(t, bidder, &openrtb2.BidRequest{}, http.StatusOK, []byte("not-json")) + assert.Nil(t, resp) + require.Len(t, errs, 1) + assert.True(t, isBadServerErr(errs[0]), "got %T", errs[0]) + }) +} + +// TestMakeRequests_NoImps — empty Imp slice returns (nil, nil) before any work +// happens. +func TestMakeRequests_NoImps(t *testing.T) { + bidder := newTealBidder(t) + requests, errs := bidder.MakeRequests(&openrtb2.BidRequest{ID: "req"}, &adapters.ExtraRequestInfo{}) + assert.Nil(t, requests) + assert.Nil(t, errs) +} + +// TestGetBidType_Undeterminable — getBidType returns an explicit error (not a +// silent banner default) when the imp is missing or declares no media type, so +// MakeBids can skip the bid and surface the issue in logs. +func TestGetBidType_Undeterminable(t *testing.T) { + bid := &openrtb2.Bid{ImpID: "imp1"} + + t.Run("imp not found", func(t *testing.T) { + _, err := getBidType(bid, map[string]openrtb2.Imp{}) + require.Error(t, err) + assert.Contains(t, err.Error(), `failed to determine bid type for imp "imp1"`) + }) + + t.Run("imp has no media type", func(t *testing.T) { + imp := openrtb2.Imp{ID: "imp1"} + _, err := getBidType(bid, map[string]openrtb2.Imp{imp.ID: imp}) + require.Error(t, err) + assert.Contains(t, err.Error(), `failed to determine bid type for imp "imp1"`) + }) +} + +// TestModifyImp_MalformedExt — modifyImp's parse-error branch. Unreachable via +// MakeRequests (parseImpExt rejects non-object imp.ext first), so it cannot be +// a fixture. +func TestModifyImp_MalformedExt(t *testing.T) { + imp := &openrtb2.Imp{ID: "broken", Ext: json.RawMessage(`not-json`)} + got, err := modifyImp(imp, strPtr("p")) + assert.Nil(t, got) + require.Error(t, err) + assert.Contains(t, err.Error(), "Error parsing imp.ext for impression broken") +} + +// TestDecodeOrEmptyObject — the non-object branch is unreachable via +// MakeRequests (parseImpExt rejects those shapes first); the returned map must +// never be nil so callers can assign into it. +func TestDecodeOrEmptyObject(t *testing.T) { + t.Run("empty raw returns empty map", func(t *testing.T) { + out := decodeOrEmptyObject(nil) + assert.NotNil(t, out) + assert.Empty(t, out) + }) + + t.Run("non-object input returns empty map", func(t *testing.T) { + out := decodeOrEmptyObject(json.RawMessage(`[1,2,3]`)) + assert.NotNil(t, out) + assert.Empty(t, out) + }) + + t.Run("valid object input returns populated map", func(t *testing.T) { + out := decodeOrEmptyObject(json.RawMessage(`{"a":1,"b":"two"}`)) + assert.Len(t, out, 2) + assert.JSONEq(t, `1`, string(out["a"])) + assert.JSONEq(t, `"two"`, string(out["b"])) + }) +} + +// TestMergeBidsPBSFlag — pins the null-handling contract: a JSON literal `null` +// (or absent) ext must route through decodeJSONObject so the receiver map is +// non-nil before `ext["bids"] = ...`, which would otherwise panic with +// "assignment to entry in nil map". +func TestMergeBidsPBSFlag(t *testing.T) { + t.Run("null ext treated as empty object", func(t *testing.T) { + out, err := mergeBidsPBSFlag(json.RawMessage(`null`)) + require.NoError(t, err) + require.NotNil(t, out) + + var decoded map[string]json.RawMessage + require.NoError(t, json.Unmarshal(out, &decoded)) + assert.Len(t, decoded, 1, "null input should produce just the bids stamp") + assert.JSONEq(t, `{"pbs":1}`, string(decoded["bids"])) + }) + + t.Run("malformed ext returns wrapped error", func(t *testing.T) { + out, err := mergeBidsPBSFlag(json.RawMessage(`{"bids":`)) + assert.Nil(t, out) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed parsing request.ext") + }) +} + +// --------------------------------------------------------------------------- +// Test helpers +// --------------------------------------------------------------------------- + +// strPtr returns a pointer to s. Used for the *string Placement field. +func strPtr(s string) *string { + return &s +} + +// newTealBidder builds the adapter via the canonical Builder. +func newTealBidder(t *testing.T) adapters.Bidder { + t.Helper() + bidder, err := Builder(openrtb_ext.BidderTeal, config.Adapter{Endpoint: testEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + require.NoError(t, err) + require.NotNil(t, bidder) + return bidder +} + +// givenImpExt produces the imp.ext shape Teal expects: {"bidder": ExtImpTeal}. +func givenImpExt(t *testing.T, account string, placement *string) json.RawMessage { + t.Helper() + inner := openrtb_ext.ExtImpTeal{Account: account, Placement: placement} + innerJSON, err := json.Marshal(inner) + require.NoError(t, err) + wrapper := map[string]json.RawMessage{"bidder": innerJSON} + out, err := json.Marshal(wrapper) + require.NoError(t, err) + return out +} + +// givenBannerImp returns a single banner imp with the supplied id and ext. +func givenBannerImp(id string, ext json.RawMessage) openrtb2.Imp { + return openrtb2.Imp{ + ID: id, + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Ext: ext, + } +} + +// givenBidRequest returns a minimal site-rooted BidRequest with the given imps. +func givenBidRequest(imps ...openrtb2.Imp) *openrtb2.BidRequest { + return &openrtb2.BidRequest{ + ID: testRequestID, + Imp: imps, + Site: &openrtb2.Site{ID: "demo-site", Publisher: &openrtb2.Publisher{ID: "demo-publisher"}}, + } +} + +// makeBidsCall wires a ResponseData and invokes MakeBids. +func makeBidsCall(t *testing.T, bidder adapters.Bidder, request *openrtb2.BidRequest, status int, body []byte) (*adapters.BidderResponse, []error) { + t.Helper() + return bidder.MakeBids(request, &adapters.RequestData{Method: http.MethodPost, Uri: testEndpoint}, + &adapters.ResponseData{StatusCode: status, Body: body}) +} + +// isBadInputErr returns true if err is or wraps an *errortypes.BadInput. +func isBadInputErr(err error) bool { + var target *errortypes.BadInput + return errors.As(err, &target) +} + +// isBadServerErr returns true if err is or wraps an *errortypes.BadServerResponse. +func isBadServerErr(err error) bool { + var target *errortypes.BadServerResponse + return errors.As(err, &target) +} diff --git a/adapters/teal/tealtest/exemplary/app-publisher-rewrite.json b/adapters/teal/tealtest/exemplary/app-publisher-rewrite.json new file mode 100644 index 0000000000..25a46fb874 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/app-publisher-rewrite.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "app": { + "id": "demo-app", + "name": "Demo App", + "bundle": "com.example.demoapp", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36", + "ip": "192.0.2.10", + "language": "en", + "ifa": "demo-ifa" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "app": { + "id": "demo-app", + "name": "Demo App", + "bundle": "com.example.demoapp", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36", + "ip": "192.0.2.10", + "language": "en", + "ifa": "demo-ifa" + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "app-bid-1", + "impid": "test-imp-banner", + "price": 3.10, + "adm": "<div>app-banner</div>", + "w": 300, + "h": 250, + "crid": "app-creative-9" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "app-bid-1", + "impid": "test-imp-banner", + "price": 3.10, + "adm": "<div>app-banner</div>", + "w": 300, + "h": 250, + "crid": "app-creative-9" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/existing-request-ext.json b/adapters/teal/tealtest/exemplary/existing-request-ext.json new file mode 100644 index 0000000000..7c21c085f0 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/existing-request-ext.json @@ -0,0 +1,135 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "ext": { + "tealcustom": "preserve-me", + "prebid": { + "channel": { + "name": "web" + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + }, + "prebid": { + "channel": { + "name": "web" + } + }, + "tealcustom": "preserve-me" + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "ext-bid", + "impid": "test-imp-banner", + "price": 1.75, + "adm": "<div>ext-preserved</div>", + "w": 300, + "h": 250, + "crid": "ext-creative" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "ext-bid", + "impid": "test-imp-banner", + "price": 1.75, + "adm": "<div>ext-preserved</div>", + "w": 300, + "h": 250, + "crid": "ext-creative" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/multi-format-imp-mtype.json b/adapters/teal/tealtest/exemplary/multi-format-imp-mtype.json new file mode 100644 index 0000000000..e8114b1969 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/multi-format-imp-mtype.json @@ -0,0 +1,173 @@ +{ + "mockBidRequest": { + "id": "test-request-multi-format-mtype", + "imp": [ + { + "id": "test-imp-multi-format", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "native": { + "request": "{\"ver\":\"1.2\"}" + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-multi" + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-multi-format-mtype", + "imp": [ + { + "id": "test-imp-multi-format", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "native": { + "request": "{\"ver\":\"1.2\"}" + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-multi" + }, + "prebid": { + "storedrequest": { + "id": "test-placement-multi" + } + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-multi-format"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-multi-format-mtype", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-banner", + "impid": "test-imp-multi-format", + "price": 1.75, + "adm": "<div>Teal Banner Ad</div>", + "mtype": 1, + "crid": "creative-banner" + }, + { + "id": "bid-video", + "impid": "test-imp-multi-format", + "price": 2.10, + "adm": "<VAST>Teal Video Ad</VAST>", + "mtype": 2, + "crid": "creative-video" + }, + { + "id": "bid-native", + "impid": "test-imp-multi-format", + "price": 0.90, + "adm": "{\"native\":{\"assets\":[]}}", + "mtype": 4, + "crid": "creative-native" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-banner", + "impid": "test-imp-multi-format", + "price": 1.75, + "adm": "<div>Teal Banner Ad</div>", + "mtype": 1, + "crid": "creative-banner" + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-video", + "impid": "test-imp-multi-format", + "price": 2.10, + "adm": "<VAST>Teal Video Ad</VAST>", + "mtype": 2, + "crid": "creative-video" + }, + "type": "video" + }, + { + "bid": { + "id": "bid-native", + "impid": "test-imp-multi-format", + "price": 0.90, + "adm": "{\"native\":{\"assets\":[]}}", + "mtype": 4, + "crid": "creative-native" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/multi-format-imp.json b/adapters/teal/tealtest/exemplary/multi-format-imp.json new file mode 100644 index 0000000000..534711f492 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/multi-format-imp.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "test-request-multi-format", + "imp": [ + { + "id": "test-imp-multi-format", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-multi" + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-multi-format", + "imp": [ + { + "id": "test-imp-multi-format", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-multi" + }, + "prebid": { + "storedrequest": { + "id": "test-placement-multi" + } + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-multi-format"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-multi-format", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-multi-format", + "impid": "test-imp-multi-format", + "price": 1.75, + "adm": "<div>Teal Multi-Format Ad</div>", + "w": 300, + "h": 250, + "crid": "creative-multi" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-multi-format", + "impid": "test-imp-multi-format", + "price": 1.75, + "adm": "<div>Teal Multi-Format Ad</div>", + "w": 300, + "h": 250, + "crid": "creative-multi" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/multi-imp-same-account.json b/adapters/teal/tealtest/exemplary/multi-imp-same-account.json new file mode 100644 index 0000000000..978b639a14 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/multi-imp-same-account.json @@ -0,0 +1,181 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "shared-account", + "placement": "placement-1" + } + } + }, + { + "id": "test-imp-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "account": "shared-account", + "placement": "placement-2" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "shared-account", + "placement": "placement-1" + }, + "prebid": { + "storedrequest": { + "id": "placement-1" + } + } + } + }, + { + "id": "test-imp-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "account": "shared-account", + "placement": "placement-2" + }, + "prebid": { + "storedrequest": { + "id": "placement-2" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "shared-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-1", "test-imp-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-1", + "price": 1.10, + "adm": "<div>imp1</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + { + "id": "bid-2", + "impid": "test-imp-2", + "price": 0.80, + "adm": "<div>imp2</div>", + "w": 728, + "h": 90, + "crid": "c2" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-1", + "price": 1.10, + "adm": "<div>imp1</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-2", + "impid": "test-imp-2", + "price": 0.80, + "adm": "<div>imp2</div>", + "w": 728, + "h": 90, + "crid": "c2" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/native-imp.json b/adapters/teal/tealtest/exemplary/native-imp.json new file mode 100644 index 0000000000..10012c7001 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/native-imp.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "id": "test-request-native", + "imp": [ + { + "id": "test-imp-native", + "native": { + "request": "{\"ver\":\"1.1\"}" + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-native" + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": {"id": "demo-publisher"} + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-native", + "imp": [ + { + "id": "test-imp-native", + "native": {"request": "{\"ver\":\"1.1\"}"}, + "ext": { + "bidder": {"account": "test-account", "placement": "test-placement-native"}, + "prebid": {"storedrequest": {"id": "test-placement-native"}} + } + } + ], + "site": {"id": "demo-site", "publisher": {"id": "test-account"}}, + "ext": {"bids": {"pbs": 1}} + }, + "impIDs": ["test-imp-native"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-native", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-native-1", + "impid": "test-imp-native", + "price": 1.0, + "adm": "{\"native\":{\"assets\":[]}}" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-native-1", + "impid": "test-imp-native", + "price": 1.0, + "adm": "{\"native\":{\"assets\":[]}}" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/placement-absent.json b/adapters/teal/tealtest/exemplary/placement-absent.json new file mode 100644 index 0000000000..3271695bb5 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/placement-absent.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-no-placement", + "impid": "test-imp-banner", + "price": 0.95, + "adm": "<div>no-placement</div>", + "w": 300, + "h": 250, + "crid": "creative-np" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-no-placement", + "impid": "test-imp-banner", + "price": 0.95, + "adm": "<div>no-placement</div>", + "w": 300, + "h": 250, + "crid": "creative-np" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/preserves-existing-imp-ext-prebid.json b/adapters/teal/tealtest/exemplary/preserves-existing-imp-ext-prebid.json new file mode 100644 index 0000000000..daf2d0c2e7 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/preserves-existing-imp-ext-prebid.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "foo": "bar", + "keyword": "keep-me", + "storedrequest": { + "unrelated": "value" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "foo": "bar", + "keyword": "keep-me", + "storedrequest": { + "unrelated": "value", + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/simple-banner.json b/adapters/teal/tealtest/exemplary/simple-banner.json new file mode 100644 index 0000000000..b143c66ed8 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/simple-banner.json @@ -0,0 +1,171 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-imp-banner", + "impid": "test-imp-banner", + "price": 2.50, + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Teal Demo Ad</div>", + "w": 300, + "h": 250, + "crid": "demo-creative-123", + "exp": 300, + "ext": { + "origbidcpm": 2.50, + "origbidcur": "USD", + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "teal" + } + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-imp-banner", + "impid": "test-imp-banner", + "price": 2.50, + "adm": "<div style=\"width:300px;height:250px;background:#f0f0f0;text-align:center;line-height:250px;\">Teal Demo Ad</div>", + "w": 300, + "h": 250, + "crid": "demo-creative-123", + "exp": 300, + "ext": { + "origbidcpm": 2.50, + "origbidcur": "USD", + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "teal" + } + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/site-no-publisher.json b/adapters/teal/tealtest/exemplary/site-no-publisher.json new file mode 100644 index 0000000000..c4f4415439 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/site-no-publisher.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": {"format": [{"w": 300, "h": 250}]}, + "ext": { + "bidder": {"account": "test-account", "placement": "test-placement300x250"}, + "prebid": {"storedrequest": {"id": "test-placement300x250"}} + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "publisher": {"id": "test-account"} + }, + "ext": {"bids": {"pbs": 1}} + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 2.0, + "w": 300, + "h": 250 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 2.0, + "w": 300, + "h": 250 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/exemplary/video-imp.json b/adapters/teal/tealtest/exemplary/video-imp.json new file mode 100644 index 0000000000..de91ee3235 --- /dev/null +++ b/adapters/teal/tealtest/exemplary/video-imp.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-video", + "imp": [ + { + "id": "test-imp-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-video" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-video", + "imp": [ + { + "id": "test-imp-video", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement-video" + }, + "prebid": { + "storedrequest": { + "id": "test-placement-video" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-video", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "video-bid-1", + "impid": "test-imp-video", + "price": 4.50, + "adm": "<VAST version=\"3.0\"></VAST>", + "w": 640, + "h": 480, + "crid": "video-creative-22" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "video-bid-1", + "impid": "test-imp-video", + "price": 4.50, + "adm": "<VAST version=\"3.0\"></VAST>", + "w": 640, + "h": 480, + "crid": "video-creative-22" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/bid-unmatched-imp-skipped.json b/adapters/teal/tealtest/supplemental/bid-unmatched-imp-skipped.json new file mode 100644 index 0000000000..fd6db866a6 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/bid-unmatched-imp-skipped.json @@ -0,0 +1,134 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "good-bid", + "impid": "test-imp-banner", + "price": 1.25, + "adm": "<div>kept</div>", + "w": 300, + "h": 250, + "crid": "creative-1" + }, + { + "id": "orphan-bid", + "impid": "no-such-imp", + "price": 0.99, + "adm": "<div>skipped</div>", + "crid": "creative-2" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "good-bid", + "impid": "test-imp-banner", + "price": 1.25, + "adm": "<div>kept</div>", + "w": 300, + "h": 250, + "crid": "creative-1" + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "failed to determine bid type for imp \"no-such-imp\"", + "comparison": "literal" + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/both-site-and-app.json b/adapters/teal/tealtest/supplemental/both-site-and-app.json new file mode 100644 index 0000000000..c19fee1396 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/both-site-and-app.json @@ -0,0 +1,135 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "site-pub" + } + }, + "app": { + "id": "demo-app", + "bundle": "com.demo.app", + "publisher": { + "id": "app-pub" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "app": { + "id": "demo-app", + "bundle": "com.demo.app", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/empty-seatbid.json b/adapters/teal/tealtest/supplemental/empty-seatbid.json new file mode 100644 index 0000000000..c7b2888b70 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/empty-seatbid.json @@ -0,0 +1,83 @@ +{ + "mockBidRequest": { + "id": "test-request-empty-seatbid", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account" + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-empty-seatbid", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account" + } + } + } + ], + "site": { + "id": "demo-site", + "publisher": { + "id": "test-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-empty-seatbid", + "cur": "USD", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/malformed-body.json b/adapters/teal/tealtest/supplemental/malformed-body.json new file mode 100644 index 0000000000..1c535d52bc --- /dev/null +++ b/adapters/teal/tealtest/supplemental/malformed-body.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + }, + "id": "test-imp-banner" + } + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": [ + "test-imp-banner" + ] + }, + "mockResponse": { + "status": 200, + "body": "this is not json" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/mixed-imp-partial-failure.json b/adapters/teal/tealtest/supplemental/mixed-imp-partial-failure.json new file mode 100644 index 0000000000..7943c744a5 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/mixed-imp-partial-failure.json @@ -0,0 +1,156 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + }, + { + "id": "test-imp-bad", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "account": "", + "placement": "test-placement728x90" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "good-bid", + "impid": "test-imp-banner", + "price": 1.25, + "adm": "<div>partial-success</div>", + "w": 300, + "h": 250, + "crid": "creative-1" + } + ] + } + ] + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "account parameter failed validation", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "good-bid", + "impid": "test-imp-banner", + "price": 1.25, + "adm": "<div>partial-success</div>", + "w": 300, + "h": 250, + "crid": "creative-1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/multi-imp-divergent-account-rejected.json b/adapters/teal/tealtest/supplemental/multi-imp-divergent-account-rejected.json new file mode 100644 index 0000000000..a4df97da64 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/multi-imp-divergent-account-rejected.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "first-account", + "placement": "placement-1" + } + } + }, + { + "id": "test-imp-2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "account": "second-account", + "placement": "placement-2" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "first-account", + "placement": "placement-1" + }, + "prebid": { + "storedrequest": { + "id": "placement-1" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "first-account" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-1", + "price": 1.10, + "adm": "<div>imp1</div>", + "w": 300, + "h": 250, + "crid": "c1" + } + ] + } + ] + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "mixed-account requests are not supported: imp \"test-imp-2\" account \"second-account\" differs from request account \"first-account\"", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-1", + "price": 1.10, + "adm": "<div>imp1</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/multi-seatbid.json b/adapters/teal/tealtest/supplemental/multi-seatbid.json new file mode 100644 index 0000000000..964b37c14d --- /dev/null +++ b/adapters/teal/tealtest/supplemental/multi-seatbid.json @@ -0,0 +1,194 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "multi-acct", + "placement": "pb" + } + } + }, + { + "id": "imp-video", + "video": { + "mimes": ["video/mp4"] + }, + "ext": { + "bidder": { + "account": "multi-acct", + "placement": "pv" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "multi-acct", + "placement": "pb" + }, + "prebid": { + "storedrequest": { + "id": "pb" + } + } + } + }, + { + "id": "imp-video", + "video": { + "mimes": ["video/mp4"] + }, + "ext": { + "bidder": { + "account": "multi-acct", + "placement": "pv" + }, + "prebid": { + "storedrequest": { + "id": "pv" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "multi-acct" + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["imp-banner", "imp-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "EUR", + "seatbid": [ + { + "seat": "s1", + "bid": [ + { + "id": "b1", + "impid": "imp-banner", + "price": 1.00, + "adm": "<div>banner</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + { + "id": "b2", + "impid": "imp-video", + "price": 2.00, + "adm": "<VAST/>", + "crid": "c2" + } + ] + }, + { + "seat": "s2", + "bid": [ + { + "id": "b3", + "impid": "imp-banner", + "price": 1.50, + "adm": "<div>banner2</div>", + "w": 300, + "h": 250, + "crid": "c3" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "b1", + "impid": "imp-banner", + "price": 1.00, + "adm": "<div>banner</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + }, + { + "bid": { + "id": "b2", + "impid": "imp-video", + "price": 2.00, + "adm": "<VAST/>", + "crid": "c2" + }, + "type": "video" + }, + { + "bid": { + "id": "b3", + "impid": "imp-banner", + "price": 1.50, + "adm": "<div>banner2</div>", + "w": 300, + "h": 250, + "crid": "c3" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/no-response-body.json b/adapters/teal/tealtest/supplemental/no-response-body.json new file mode 100644 index 0000000000..203d5674b5 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/no-response-body.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + }, + "id": "test-imp-banner" + } + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": [ + "test-imp-banner" + ] + }, + "mockResponse": { + "status": 200 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found", + "comparison": "startswith" + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/no-site-no-app.json b/adapters/teal/tealtest/supplemental/no-site-no-app.json new file mode 100644 index 0000000000..051e8f026e --- /dev/null +++ b/adapters/teal/tealtest/supplemental/no-site-no-app.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": ["test-imp-banner"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-banner", + "price": 1.50, + "adm": "<div>ad</div>", + "w": 300, + "h": 250, + "crid": "c1" + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/status-204.json b/adapters/teal/tealtest/supplemental/status-204.json new file mode 100644 index 0000000000..22cdc1ad7d --- /dev/null +++ b/adapters/teal/tealtest/supplemental/status-204.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + }, + "id": "test-imp-banner" + } + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": [ + "test-imp-banner" + ] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/teal/tealtest/supplemental/status-400.json b/adapters/teal/tealtest/supplemental/status-400.json new file mode 100644 index 0000000000..28b430674c --- /dev/null +++ b/adapters/teal/tealtest/supplemental/status-400.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + }, + "id": "test-imp-banner" + } + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": [ + "test-imp-banner" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/teal/tealtest/supplemental/status-404.json b/adapters/teal/tealtest/supplemental/status-404.json new file mode 100644 index 0000000000..9e3c8f9a63 --- /dev/null +++ b/adapters/teal/tealtest/supplemental/status-404.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "ip": "192.0.2.1", + "language": "en", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "id": "test-request-banner", + "imp": [ + { + "banner": { + "format": [ + { + "h": 250, + "w": 300 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + } + }, + "id": "test-imp-banner" + } + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "site": { + "domain": "example.com", + "id": "demo-site", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "user": { + "id": "demo-user" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.example.com/bid", + "body": { + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "account": "test-account", + "placement": "test-placement300x250" + }, + "prebid": { + "storedrequest": { + "id": "test-placement300x250" + } + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "test-account" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "bids": { + "pbs": 1 + } + } + }, + "impIDs": [ + "test-imp-banner" + ] + }, + "mockResponse": { + "status": 404, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 75a848b759..8e6e0cd061 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -231,6 +231,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/tappx" "github.com/prebid/prebid-server/v4/adapters/targetVideo" "github.com/prebid/prebid-server/v4/adapters/teads" + "github.com/prebid/prebid-server/v4/adapters/teal" "github.com/prebid/prebid-server/v4/adapters/telaria" "github.com/prebid/prebid-server/v4/adapters/teqblaze" "github.com/prebid/prebid-server/v4/adapters/theadx" @@ -506,6 +507,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderTappx: tappx.Builder, openrtb_ext.BidderTargetVideo: targetVideo.Builder, openrtb_ext.BidderTeads: teads.Builder, + openrtb_ext.BidderTeal: teal.Builder, openrtb_ext.BidderTelaria: telaria.Builder, openrtb_ext.BidderTeqBlaze: teqblaze.Builder, openrtb_ext.BidderTheadx: theadx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index aa725e7d1b..0c8e92672c 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -249,6 +249,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderTappx, BidderTargetVideo, BidderTeads, + BidderTeal, BidderTelaria, BidderTeqBlaze, BidderTheadx, @@ -628,6 +629,7 @@ const ( BidderTappx BidderName = "tappx" BidderTargetVideo BidderName = "targetVideo" BidderTeads BidderName = "teads" + BidderTeal BidderName = "teal" BidderTelaria BidderName = "telaria" BidderTeqBlaze BidderName = "teqblaze" BidderTheadx BidderName = "theadx" diff --git a/openrtb_ext/imp_teal.go b/openrtb_ext/imp_teal.go new file mode 100644 index 0000000000..9f961c33b1 --- /dev/null +++ b/openrtb_ext/imp_teal.go @@ -0,0 +1,17 @@ +package openrtb_ext + +// ExtImpTeal carries the per-imp Teal bidder-slot params. +// +// Account is required. The first valid imp's account is propagated to +// BidRequest.Site.Publisher.ID (and BidRequest.App.Publisher.ID, when present). +// All imps in a request must use the same account: a later imp whose account +// differs is rejected with a BadInput error and dropped. +// +// Placement is optional. When present and non-blank, the adapter injects +// imp.ext.prebid.storedrequest.id = placement on a per-imp basis. Pointer-typed +// to distinguish absent (nil) from present-but-blank (non-nil → validation +// failure). +type ExtImpTeal struct { + Account string `json:"account"` + Placement *string `json:"placement,omitempty"` +} diff --git a/static/bidder-info/teal.yaml b/static/bidder-info/teal.yaml new file mode 100644 index 0000000000..6f6bf74dd9 --- /dev/null +++ b/static/bidder-info/teal.yaml @@ -0,0 +1,27 @@ +endpoint: "https://a.bids.ws/openrtb2/auction" +maintainer: + email: prebid@teal.works +gvlVendorID: 1378 +endpointCompression: gzip +modifyingVastXmlAllowed: true +geoscope: + - global +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + key: "teal" + iframe: + url: "https://bids.ws/load-pbs.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect_url={{.RedirectURL}}" +openrtb: + version: 2.6 + multiformat-supported: true + gpp-supported: true diff --git a/static/bidder-params/teal.json b/static/bidder-params/teal.json new file mode 100644 index 0000000000..217dd083d3 --- /dev/null +++ b/static/bidder-params/teal.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Teal Adapter Params", + "description": "A schema which validates params accepted by the Teal adapter", + "type": "object", + "properties": { + "account": { + "type": "string", + "minLength": 1, + "description": "Account ID" + }, + "placement": { + "type": "string", + "minLength": 1, + "description": "Placement ID or name (optional)" + } + }, + "required": [ + "account" + ] +} From caaa6fd43c5efce9e2a771f37c74c319bc190012 Mon Sep 17 00:00:00 2001 From: quietPusher <129727954+quietPusher@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:58:44 +0200 Subject: [PATCH 245/272] New Adapter: Nuclion - Limelight Alias (#4751) Co-authored-by: apykhteyev <alex@project-limelight.com> Co-authored-by: mderevyanko <mderevyanko24@gmail.com> --- static/bidder-info/nuclion.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 static/bidder-info/nuclion.yaml diff --git a/static/bidder-info/nuclion.yaml b/static/bidder-info/nuclion.yaml new file mode 100644 index 0000000000..070512409b --- /dev/null +++ b/static/bidder-info/nuclion.yaml @@ -0,0 +1,2 @@ +endpoint: "http://ads-pbs.rtb-nuclion.io/openrtb/{{.PublisherID}}?host={{.Host}}" +aliasOf: "limelightDigital" From 4176778b8febe685f6888528e70f381bf1070fd3 Mon Sep 17 00:00:00 2001 From: BaronJHYu <254878848@qq.com> Date: Sun, 26 Jul 2026 03:35:07 +0800 Subject: [PATCH 246/272] New Adapter: MediaGo Technology - MediaGo Alias (#4842) --- static/bidder-info/mgtechnology.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 static/bidder-info/mgtechnology.yaml diff --git a/static/bidder-info/mgtechnology.yaml b/static/bidder-info/mgtechnology.yaml new file mode 100644 index 0000000000..24e8544a74 --- /dev/null +++ b/static/bidder-info/mgtechnology.yaml @@ -0,0 +1,25 @@ +# MediaGo Technology LLC - alias of mediago with separate endpoint, GVL ID, and user sync +aliasOf: mediago +endpoint: "https://gbid.mediagotechnology.com/api/bid?tn={{.AccountID}}" +endpointCompression: gzip +geoscope: + - USA + - DEU + - JPN + - GBR + - KOR + - CAN + - FRA + - ITA +maintainer: + email: ext_mediago_cm@baidu.com +gvlVendorID: 1575 +capabilities: + site: + mediaTypes: + - banner + - native +userSync: + redirect: + url: https://go.mediagotechnology.com/ju/cs/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID From 504f46bf7e578b970e6daad46ddc2e29a90900e9 Mon Sep 17 00:00:00 2001 From: sangarbe <sangarbe@gmail.com> Date: Tue, 4 Aug 2026 16:20:37 +0200 Subject: [PATCH 247/272] Seedtag: RON id support (#4744) --- adapters/seedtag/params_test.go | 6 + .../seedtag/seedtagtest/exemplary/ron_id.json | 128 ++++++++++++++++++ openrtb_ext/imp_seedtag.go | 4 +- static/bidder-params/seedtag.json | 23 +++- 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 adapters/seedtag/seedtagtest/exemplary/ron_id.json diff --git a/adapters/seedtag/params_test.go b/adapters/seedtag/params_test.go index 2c39237739..f8a6eff8dd 100644 --- a/adapters/seedtag/params_test.go +++ b/adapters/seedtag/params_test.go @@ -35,10 +35,16 @@ func TestInvalidParams(t *testing.T) { var validParams = []string{ `{"adUnitId": "27604970"}`, + `{"publisherId": "abc123", "integrationType": "ronId"}`, } var invalidParams = []string{ `{"adUnitId": 123}`, `{"adUnitId": ""}`, `{}`, + `{"publisherId": "abc123"}`, + `{"integrationType": "ronId"}`, + `{"publisherId": "", "integrationType": "ronId"}`, + `{"publisherId": "abc123", "integrationType": "unknown"}`, + `{"adUnitId": "27604970", "publisherId": "abc123", "integrationType": "ronId"}`, } diff --git a/adapters/seedtag/seedtagtest/exemplary/ron_id.json b/adapters/seedtag/seedtagtest/exemplary/ron_id.json new file mode 100644 index 0000000000..f09c9b9b3e --- /dev/null +++ b/adapters/seedtag/seedtagtest/exemplary/ron_id.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "publisher": { + "id": "foo", + "name": "foo" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "abc123", + "integrationType": "ronId" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://url.seedtag.com", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, + "body": { + "cur": ["USD"], + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "abc123", + "integrationType": "ronId" + } + } + } + ], + "site": { + "publisher": { + "id": "foo", + "name": "foo" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "123", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adid": "12341234", + "adm": "some-test-ad", + "adomain": [ + "domain.com" + ], + "iurl": "http://abc.com/cr?id=12341234", + "cid": "123", + "crid": "12341234", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "12341234", + "adomain": [ + "domain.com" + ], + "iurl": "http://abc.com/cr?id=12341234", + "cid": "123", + "crid": "12341234", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/openrtb_ext/imp_seedtag.go b/openrtb_ext/imp_seedtag.go index 825595dd29..4a235cb986 100644 --- a/openrtb_ext/imp_seedtag.go +++ b/openrtb_ext/imp_seedtag.go @@ -1,5 +1,7 @@ package openrtb_ext type ImpExtSeedtag struct { - AdUnitID string `json:"adUnitId"` + AdUnitID string `json:"adUnitId,omitempty"` + PublisherID string `json:"publisherId,omitempty"` + IntegrationType string `json:"integrationType,omitempty"` } diff --git a/static/bidder-params/seedtag.json b/static/bidder-params/seedtag.json index 7f361c44f9..677fb9fba2 100644 --- a/static/bidder-params/seedtag.json +++ b/static/bidder-params/seedtag.json @@ -6,11 +6,26 @@ "properties": { "adUnitId": { "type": "string", - "description": "Ad Unit ID", + "description": "Ad Unit ID for the placement", "minLength": 1 + }, + "publisherId": { + "type": "string", + "description": "Publisher group ID for RON integration", + "minLength": 1 + }, + "integrationType": { + "type": "string", + "description": "Integration type. Use 'ronId' when integrating via publisherToken", + "enum": ["ronId"] } }, - "required": [ - "adUnitId" + "oneOf": [ + { + "required": ["adUnitId"] + }, + { + "required": ["publisherId", "integrationType"] + } ] -} \ No newline at end of file +} From 0147ea3fdae740bc43c52113288e1f8d3289401a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abdulbaki=20=C3=87am?= <71071893+bakicam@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:34:27 +0300 Subject: [PATCH 248/272] New Adapter: AdRubi - Admatic alias (#4808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Faruk Çam <mail@farukix.com> --- static/bidder-info/adrubi.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/adrubi.yaml diff --git a/static/bidder-info/adrubi.yaml b/static/bidder-info/adrubi.yaml new file mode 100644 index 0000000000..1d19dc7521 --- /dev/null +++ b/static/bidder-info/adrubi.yaml @@ -0,0 +1,4 @@ +aliasOf: "admatic" +maintainer: + email: "support@adrubi.com" +gvlVendorID: 779 \ No newline at end of file From 93c33deeec8391d4208d208ee226d0a7b74f5a88 Mon Sep 17 00:00:00 2001 From: Andrius Versockas <andrius.versockas@gmail.com> Date: Tue, 4 Aug 2026 17:46:49 +0300 Subject: [PATCH 249/272] New Adapter: Eskimi (#4806) Co-authored-by: Andrius Versockas <andrius.v@eskimi.com> --- adapters/eskimi/eskimi.go | 259 ++++++++++++++++++ adapters/eskimi/eskimi_test.go | 157 +++++++++++ .../exemplary/banner-web-with-buyeruid.json | 94 +++++++ .../eskimitest/exemplary/multi-imp-web.json | 162 +++++++++++ .../eskimitest/exemplary/optional-params.json | 120 ++++++++ .../exemplary/simple-banner-app.json | 112 ++++++++ .../exemplary/simple-banner-web.json | 104 +++++++ .../exemplary/simple-video-app.json | 116 ++++++++ .../exemplary/simple-video-web.json | 108 ++++++++ .../supplemental/app-ext-merge.json | 71 +++++ .../supplemental/invalid-bidder-params.json | 20 ++ .../supplemental/invalid-imp-ext.json | 20 ++ .../supplemental/invalid-response-body.json | 50 ++++ .../multi-format-imp-battr-dual-write.json | 86 ++++++ .../multi-format-imp-uses-mtype.json | 74 +++++ ...multi-format-imp-without-mtype-errors.json | 76 +++++ .../supplemental/multi-imp-asymmetry.json | 103 +++++++ .../multi-imp-invalid-second-dropped.json | 79 ++++++ .../supplemental/no-site-or-app.json | 19 ++ .../pre-set-overrides-not-clobbered.json | 96 +++++++ .../privacy-signals-pass-through.json | 89 ++++++ .../eskimitest/supplemental/response-204.json | 41 +++ .../eskimitest/supplemental/response-400.json | 46 ++++ .../eskimitest/supplemental/response-500.json | 46 ++++ .../supplemental/response-no-cur.json | 59 ++++ .../supplemental/schain-pass-through.json | 80 ++++++ .../supplemental/site-ext-merge.json | 71 +++++ .../supplemental/unmatched-bid-impid.json | 64 +++++ .../unsupported-bid-media-type.json | 75 +++++ .../supplemental/video-no-mtype-inferred.json | 70 +++++ .../supplemental/video-outstream-web.json | 104 +++++++ adapters/eskimi/params_test.go | 56 ++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_eskimi.go | 14 + static/bidder-info/eskimi.yaml | 21 ++ static/bidder-params/eskimi.json | 44 +++ 37 files changed, 2810 insertions(+) create mode 100644 adapters/eskimi/eskimi.go create mode 100644 adapters/eskimi/eskimi_test.go create mode 100644 adapters/eskimi/eskimitest/exemplary/banner-web-with-buyeruid.json create mode 100644 adapters/eskimi/eskimitest/exemplary/multi-imp-web.json create mode 100644 adapters/eskimi/eskimitest/exemplary/optional-params.json create mode 100644 adapters/eskimi/eskimitest/exemplary/simple-banner-app.json create mode 100644 adapters/eskimi/eskimitest/exemplary/simple-banner-web.json create mode 100644 adapters/eskimi/eskimitest/exemplary/simple-video-app.json create mode 100644 adapters/eskimi/eskimitest/exemplary/simple-video-web.json create mode 100644 adapters/eskimi/eskimitest/supplemental/app-ext-merge.json create mode 100644 adapters/eskimi/eskimitest/supplemental/invalid-bidder-params.json create mode 100644 adapters/eskimi/eskimitest/supplemental/invalid-imp-ext.json create mode 100644 adapters/eskimi/eskimitest/supplemental/invalid-response-body.json create mode 100644 adapters/eskimi/eskimitest/supplemental/multi-format-imp-battr-dual-write.json create mode 100644 adapters/eskimi/eskimitest/supplemental/multi-format-imp-uses-mtype.json create mode 100644 adapters/eskimi/eskimitest/supplemental/multi-format-imp-without-mtype-errors.json create mode 100644 adapters/eskimi/eskimitest/supplemental/multi-imp-asymmetry.json create mode 100644 adapters/eskimi/eskimitest/supplemental/multi-imp-invalid-second-dropped.json create mode 100644 adapters/eskimi/eskimitest/supplemental/no-site-or-app.json create mode 100644 adapters/eskimi/eskimitest/supplemental/pre-set-overrides-not-clobbered.json create mode 100644 adapters/eskimi/eskimitest/supplemental/privacy-signals-pass-through.json create mode 100644 adapters/eskimi/eskimitest/supplemental/response-204.json create mode 100644 adapters/eskimi/eskimitest/supplemental/response-400.json create mode 100644 adapters/eskimi/eskimitest/supplemental/response-500.json create mode 100644 adapters/eskimi/eskimitest/supplemental/response-no-cur.json create mode 100644 adapters/eskimi/eskimitest/supplemental/schain-pass-through.json create mode 100644 adapters/eskimi/eskimitest/supplemental/site-ext-merge.json create mode 100644 adapters/eskimi/eskimitest/supplemental/unmatched-bid-impid.json create mode 100644 adapters/eskimi/eskimitest/supplemental/unsupported-bid-media-type.json create mode 100644 adapters/eskimi/eskimitest/supplemental/video-no-mtype-inferred.json create mode 100644 adapters/eskimi/eskimitest/supplemental/video-outstream-web.json create mode 100644 adapters/eskimi/params_test.go create mode 100644 openrtb_ext/imp_eskimi.go create mode 100644 static/bidder-info/eskimi.yaml create mode 100644 static/bidder-params/eskimi.json diff --git a/adapters/eskimi/eskimi.go b/adapters/eskimi/eskimi.go new file mode 100644 index 0000000000..0f6b3e7fd0 --- /dev/null +++ b/adapters/eskimi/eskimi.go @@ -0,0 +1,259 @@ +package eskimi + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the Eskimi adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{endpoint: config.Endpoint}, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if len(request.Imp) == 0 { + return nil, []error{&errortypes.BadInput{Message: "no impressions in the bid request"}} + } + + outgoing := *request + outgoing.Imp = append([]openrtb2.Imp(nil), request.Imp...) + + first, err := parseImpExt(outgoing.Imp[0]) + if err != nil { + return nil, []error{err} + } + + if err := setPlacementID(&outgoing, first.PlacementID); err != nil { + return nil, []error{err} + } + + applyRequestParams(&outgoing, first) + + // Imps whose ext fails to parse are dropped so malformed data is never + // forwarded upstream; the parse error is still reported to the caller. + imps := make([]openrtb2.Imp, 0, len(outgoing.Imp)) + impExts := make([]*openrtb_ext.ExtImpEskimi, 0, len(outgoing.Imp)) + imps = append(imps, outgoing.Imp[0]) + impExts = append(impExts, &first) + var errs []error + for i := 1; i < len(outgoing.Imp); i++ { + ext, perr := parseImpExt(outgoing.Imp[i]) + if perr != nil { + errs = append(errs, perr) + continue + } + imps = append(imps, outgoing.Imp[i]) + impExts = append(impExts, &ext) + } + outgoing.Imp = imps + + applyImpParams(&outgoing, impExts) + + body, err := jsonutil.Marshal(&outgoing) + if err != nil { + return nil, append(errs, err) + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.endpoint, + Body: body, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(outgoing.Imp), + }}, errs +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + var errs []error + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, typeErr := getMediaTypeForBid(request.Imp, seatBid.Bid[i]) + if typeErr != nil { + errs = append(errs, typeErr) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + return bidResponse, errs +} + +func parseImpExt(imp openrtb2.Imp) (openrtb_ext.ExtImpEskimi, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return openrtb_ext.ExtImpEskimi{}, &errortypes.BadInput{Message: fmt.Sprintf("invalid imp.ext for imp %s: %s", imp.ID, err)} + } + var eskimiExt openrtb_ext.ExtImpEskimi + if err := jsonutil.Unmarshal(bidderExt.Bidder, &eskimiExt); err != nil { + return openrtb_ext.ExtImpEskimi{}, &errortypes.BadInput{Message: fmt.Sprintf("invalid imp.ext.bidder for imp %s: %s", imp.ID, err)} + } + return eskimiExt, nil +} + +// setPlacementID writes the placement ID to site.ext.placementId or app.ext.placementId, +// preserving any other existing keys in the ext object. +func setPlacementID(request *openrtb2.BidRequest, placementID int64) error { + patch := func(ext json.RawMessage) (json.RawMessage, error) { + fields := map[string]json.RawMessage{} + if len(ext) > 0 { + if err := jsonutil.Unmarshal(ext, &fields); err != nil { + return nil, err + } + } + id, err := jsonutil.Marshal(placementID) + if err != nil { + return nil, err + } + fields["placementId"] = id + return jsonutil.Marshal(fields) + } + + switch { + case request.Site != nil: + site := *request.Site + ext, err := patch(site.Ext) + if err != nil { + return &errortypes.BadInput{Message: fmt.Sprintf("failed to set placementId on site.ext: %s", err)} + } + site.Ext = ext + request.Site = &site + case request.App != nil: + app := *request.App + ext, err := patch(app.Ext) + if err != nil { + return &errortypes.BadInput{Message: fmt.Sprintf("failed to set placementId on app.ext: %s", err)} + } + app.Ext = ext + request.App = &app + default: + return &errortypes.BadInput{Message: "request must contain either site or app"} + } + return nil +} + +// applyRequestParams promotes request-level blocklists from the first imp's bidder ext +// when the request doesn't already set them. Existing publisher/wrapper values win. +func applyRequestParams(request *openrtb2.BidRequest, ext openrtb_ext.ExtImpEskimi) { + if len(request.BCat) == 0 && len(ext.Bcat) > 0 { + request.BCat = ext.Bcat + } + if len(request.BAdv) == 0 && len(ext.Badv) > 0 { + request.BAdv = ext.Badv + } + if len(request.BApp) == 0 && len(ext.Bapp) > 0 { + request.BApp = ext.Bapp + } +} + +// applyImpParams applies per-imp params from the bidder ext: defaults imp.secure to 1, +// fills bid floor when unset, and fans out battr to both banner.battr and video.battr. +func applyImpParams(request *openrtb2.BidRequest, exts []*openrtb_ext.ExtImpEskimi) { + for i := range request.Imp { + if request.Imp[i].Secure == nil { + s := int8(1) + request.Imp[i].Secure = &s + } + ext := exts[i] + if ext == nil { + continue + } + if request.Imp[i].BidFloor == 0 && ext.BidFloor > 0 { + request.Imp[i].BidFloor = ext.BidFloor + if ext.BidFloorCur != "" { + request.Imp[i].BidFloorCur = ext.BidFloorCur + } + } + if len(ext.Battr) > 0 { + attrs := make([]adcom1.CreativeAttribute, len(ext.Battr)) + for j, v := range ext.Battr { + attrs[j] = adcom1.CreativeAttribute(v) + } + if request.Imp[i].Banner != nil && len(request.Imp[i].Banner.BAttr) == 0 { + banner := *request.Imp[i].Banner + banner.BAttr = attrs + request.Imp[i].Banner = &banner + } + if request.Imp[i].Video != nil && len(request.Imp[i].Video.BAttr) == 0 { + video := *request.Imp[i].Video + video.BAttr = attrs + request.Imp[i].Video = &video + } + } + } +} + +// getMediaTypeForBid resolves the bid's media type. When bid.mtype is set it is treated +// as authoritative; an unsupported value returns an error rather than falling back to +// imp inference. When bid.mtype is unset, the imp's media type is used; multi-format +// imps without mtype cannot be disambiguated and return an error. +func getMediaTypeForBid(imps []openrtb2.Imp, bid openrtb2.Bid) (openrtb_ext.BidType, error) { + if bid.MType != 0 { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported bid.mtype %d for impression %s (banner and video only)", bid.MType, bid.ImpID), + } + } + } + for _, imp := range imps { + if imp.ID != bid.ImpID { + continue + } + switch { + case imp.Banner != nil && imp.Video == nil: + return openrtb_ext.BidTypeBanner, nil + case imp.Video != nil && imp.Banner == nil: + return openrtb_ext.BidTypeVideo, nil + case imp.Banner != nil && imp.Video != nil: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("bid for multi-format imp %s requires bid.mtype to disambiguate", bid.ImpID), + } + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported media type for impression %s (banner and video only)", bid.ImpID), + } + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unable to resolve media type for impression %s", bid.ImpID), + } +} diff --git a/adapters/eskimi/eskimi_test.go b/adapters/eskimi/eskimi_test.go new file mode 100644 index 0000000000..c40f0bff3b --- /dev/null +++ b/adapters/eskimi/eskimi_test.go @@ -0,0 +1,157 @@ +package eskimi + +import ( + "encoding/json" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +const testEndpoint = "https://ittr.eskimi.com/prebidjs" + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderEskimi, config.Adapter{ + Endpoint: testEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 814, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "eskimitest", bidder) +} + +func newAdapter() *adapter { + return &adapter{endpoint: testEndpoint} +} + +func bannerImp(ext string) openrtb2.Imp { + return openrtb2.Imp{ + ID: "imp-1", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Ext: json.RawMessage(ext), + } +} + +func TestMalformedSiteExt(t *testing.T) { + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{bannerImp(`{"bidder":{"placementId":625}}`)}, + Site: &openrtb2.Site{ID: "271", Ext: json.RawMessage(`{invalid`)}, + } + _, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "site.ext") +} + +func TestMalformedAppExt(t *testing.T) { + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{bannerImp(`{"bidder":{"placementId":625}}`)}, + App: &openrtb2.App{ID: "app-1", Ext: json.RawMessage(`{invalid`)}, + } + _, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "app.ext") +} + +func TestImpSecureDefaultedToOne(t *testing.T) { + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{bannerImp(`{"bidder":{"placementId":625}}`)}, + Site: &openrtb2.Site{ID: "271"}, + } + reqData, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Empty(t, errs) + var out openrtb2.BidRequest + assert.NoError(t, json.Unmarshal(reqData[0].Body, &out)) + assert.NotNil(t, out.Imp[0].Secure) + assert.EqualValues(t, 1, *out.Imp[0].Secure) +} + +func TestImpSecureNotOverridden(t *testing.T) { + zero := int8(0) + imp := bannerImp(`{"bidder":{"placementId":625}}`) + imp.Secure = &zero + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{imp}, + Site: &openrtb2.Site{ID: "271"}, + } + reqData, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Empty(t, errs) + var out openrtb2.BidRequest + assert.NoError(t, json.Unmarshal(reqData[0].Body, &out)) + assert.EqualValues(t, 0, *out.Imp[0].Secure) +} + +// TestCallerRequestNotMutated asserts every copy-on-write surface in MakeRequests: +// request.{BCat,BAdv,BApp}, request.{Site,App}.Ext, request.Imp[i].Secure, +// request.Imp[i].{Banner,Video}.BAttr, and request.Imp[i].{BidFloor,BidFloorCur}. +func TestCallerRequestNotMutated(t *testing.T) { + imp := openrtb2.Imp{ + ID: "imp-1", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Video: &openrtb2.Video{MIMEs: []string{"video/mp4"}, W: openrtb2.Int64Ptr(640), H: openrtb2.Int64Ptr(480)}, + Ext: json.RawMessage(`{"bidder":{ + "placementId":625, + "bcat":["IAB1"],"badv":["bad.com"],"bapp":["com.bad"], + "bidFloor":1.5,"bidFloorCur":"EUR", + "battr":[1,2] + }}`), + } + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{imp}, + Site: &openrtb2.Site{ID: "271", Ext: json.RawMessage(`{"amp":0}`)}, + } + + _, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Empty(t, errs) + + assert.Empty(t, req.BCat, "caller's request.BCat must not be mutated") + assert.Empty(t, req.BAdv, "caller's request.BAdv must not be mutated") + assert.Empty(t, req.BApp, "caller's request.BApp must not be mutated") + assert.JSONEq(t, `{"amp":0}`, string(req.Site.Ext), "caller's request.Site.Ext must not be mutated") + assert.Nil(t, req.Imp[0].Secure, "caller's imp[0].Secure must not be mutated") + assert.EqualValues(t, 0, req.Imp[0].BidFloor, "caller's imp[0].BidFloor must not be mutated") + assert.Empty(t, req.Imp[0].BidFloorCur, "caller's imp[0].BidFloorCur must not be mutated") + assert.Empty(t, req.Imp[0].Banner.BAttr, "caller's imp[0].Banner.BAttr must not be mutated") + assert.Empty(t, req.Imp[0].Video.BAttr, "caller's imp[0].Video.BAttr must not be mutated") +} + +func TestCallerAppRequestNotMutated(t *testing.T) { + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{bannerImp(`{"bidder":{"placementId":625}}`)}, + App: &openrtb2.App{ID: "app-1", Ext: json.RawMessage(`{"installed":1}`)}, + } + _, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + assert.Empty(t, errs) + assert.JSONEq(t, `{"installed":1}`, string(req.App.Ext), "caller's request.App.Ext must not be mutated") +} + +func TestLaterImpWithInvalidExtSurfacesError(t *testing.T) { + req := &openrtb2.BidRequest{ + ID: "req-1", + Imp: []openrtb2.Imp{ + bannerImp(`{"bidder":{"placementId":625,"bidFloor":1.5,"bidFloorCur":"EUR"}}`), + {ID: "imp-2", Banner: &openrtb2.Banner{}, Ext: json.RawMessage(`"not-an-object"`)}, + }, + Site: &openrtb2.Site{ID: "271"}, + } + reqData, errs := newAdapter().MakeRequests(req, &adapters.ExtraRequestInfo{}) + // First-imp request still goes out, but the bad later imp surfaces an error. + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "imp.ext") + assert.Len(t, reqData, 1) + + var out openrtb2.BidRequest + assert.NoError(t, json.Unmarshal(reqData[0].Body, &out)) + assert.EqualValues(t, 1.5, out.Imp[0].BidFloor) +} diff --git a/adapters/eskimi/eskimitest/exemplary/banner-web-with-buyeruid.json b/adapters/eskimi/eskimitest/exemplary/banner-web-with-buyeruid.json new file mode 100644 index 0000000000..f8a3421e8b --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/banner-web-with-buyeruid.json @@ -0,0 +1,94 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com" + }, + "user": { + "buyeruid": "eskimi-dmp-id-abc-123" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + }, + "user": { + "buyeruid": "eskimi-dmp-id-abc-123" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/multi-imp-web.json b/adapters/eskimi/eskimitest/exemplary/multi-imp-web.json new file mode 100644 index 0000000000..f782fb730f --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/multi-imp-web.json @@ -0,0 +1,162 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-banner", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + }, + { + "id": "imp-video", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 999 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-banner", + "secure": 1, + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + }, + { + "id": "imp-video", + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 999 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/", + "ext": { + "placementId": 625 + } + } + }, + "impIDs": ["imp-banner", "imp-video"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "imp-banner", + "price": 1.25, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + { + "id": "2", + "impid": "imp-video", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine><Creatives><Creative><Linear><Duration>00:00:15</Duration></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "imp-banner", + "price": 1.25, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "2", + "impid": "imp-video", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine><Creatives><Creative><Linear><Duration>00:00:15</Duration></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/optional-params.json b/adapters/eskimi/eskimitest/exemplary/optional-params.json new file mode 100644 index 0000000000..350900008c --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/optional-params.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "placementId": 625, + "bidFloor": 1.5, + "bidFloorCur": "EUR", + "bcat": ["IAB1"], + "badv": ["bad.com"], + "bapp": ["com.bad.app"], + "battr": [1, 2] + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "bcat": ["IAB1"], + "badv": ["bad.com"], + "bapp": ["com.bad.app"], + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "bidfloor": 1.5, + "bidfloorcur": "EUR", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ], + "battr": [1, 2] + }, + "ext": { + "bidder": { + "placementId": 625, + "bidFloor": 1.5, + "bidFloorCur": "EUR", + "bcat": ["IAB1"], + "badv": ["bad.com"], + "bapp": ["com.bad.app"], + "battr": [1, 2] + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { + "placementId": 625 + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 2.0, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 2.0, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/simple-banner-app.json b/adapters/eskimi/eskimitest/exemplary/simple-banner-app.json new file mode 100644 index 0000000000..b8a209f2c0 --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/simple-banner-app.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { "w": 320, "h": 50 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "name": "Example App" + }, + "device": { + "ifa": "00000000-0000-0000-0000-000000000000", + "os": "Android" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { + "format": [ + { "w": 320, "h": 50 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "name": "Example App", + "ext": { + "placementId": 625 + } + }, + "device": { + "ifa": "00000000-0000-0000-0000-000000000000", + "os": "Android" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 0.9, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 320, + "h": 50, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 0.9, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/simple-banner-web.json b/adapters/eskimi/eskimitest/exemplary/simple-banner-web.json new file mode 100644 index 0000000000..44cb835683 --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/simple-banner-web.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/", + "ext": { + "placementId": 625 + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 1.25, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 1.25, + "adm": "<div>ad</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/simple-video-app.json b/adapters/eskimi/eskimitest/exemplary/simple-video-app.json new file mode 100644 index 0000000000..cafcbde9cc --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/simple-video-app.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "name": "Example App" + }, + "device": { + "ifa": "00000000-0000-0000-0000-000000000000", + "os": "Android" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "name": "Example App", + "ext": { + "placementId": 625 + } + }, + "device": { + "ifa": "00000000-0000-0000-0000-000000000000", + "os": "Android" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 5.25, + "nurl": "https://eskimi.com/win?bid=abc", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 5.25, + "nurl": "https://eskimi.com/win?bid=abc", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/exemplary/simple-video-web.json b/adapters/eskimi/eskimitest/exemplary/simple-video-web.json new file mode 100644 index 0000000000..1dff5d1adc --- /dev/null +++ b/adapters/eskimi/eskimitest/exemplary/simple-video-web.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 1 + }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "page": "https://display.eskimi-creatives.com/", + "ext": { + "placementId": 625 + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine><Creatives><Creative><Linear><Duration>00:00:15</Duration></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine><Creatives><Creative><Linear><Duration>00:00:15</Duration></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "video-creative-1", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/app-ext-merge.json b/adapters/eskimi/eskimitest/supplemental/app-ext-merge.json new file mode 100644 index 0000000000..6c80e89ea3 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/app-ext-merge.json @@ -0,0 +1,71 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 320, "h": 50 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "ext": { + "installed": 1, + "data": { "category": "games" } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 320, "h": 50 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "app": { + "id": "app-1", + "bundle": "com.eskimi.example", + "ext": { + "installed": 1, + "data": { "category": "games" }, + "placementId": 625 + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 320, "h": 50, "mtype": 1 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 320, "h": 50, "mtype": 1 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/invalid-bidder-params.json b/adapters/eskimi/eskimitest/supplemental/invalid-bidder-params.json new file mode 100644 index 0000000000..8d491d5ec3 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/invalid-bidder-params.json @@ -0,0 +1,20 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "invalid imp.ext.bidder for imp test-imp-id:.*", + "comparison": "regex" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": "not-an-object" } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [] +} diff --git a/adapters/eskimi/eskimitest/supplemental/invalid-imp-ext.json b/adapters/eskimi/eskimitest/supplemental/invalid-imp-ext.json new file mode 100644 index 0000000000..126d58f573 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/invalid-imp-ext.json @@ -0,0 +1,20 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "invalid imp.ext for imp test-imp-id:.*", + "comparison": "regex" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": "not-an-object" + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [] +} diff --git a/adapters/eskimi/eskimitest/supplemental/invalid-response-body.json b/adapters/eskimi/eskimitest/supplemental/invalid-response-body.json new file mode 100644 index 0000000000..8b7a807ddd --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/invalid-response-body.json @@ -0,0 +1,50 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": "this-should-be-an-array" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": ".*", + "comparison": "regex" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/multi-format-imp-battr-dual-write.json b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-battr-dual-write.json new file mode 100644 index 0000000000..ab2959397a --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-battr-dual-write.json @@ -0,0 +1,86 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { + "bidder": { + "placementId": 625, + "battr": [13, 14] + } + } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { + "format": [{ "w": 300, "h": 250 }], + "battr": [13, 14] + }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8], + "battr": [13, 14] + }, + "ext": { + "bidder": { + "placementId": 625, + "battr": [13, 14] + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 2.5, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480, "mtype": 2 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 2.5, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480, "mtype": 2 }, "type": "video" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/multi-format-imp-uses-mtype.json b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-uses-mtype.json new file mode 100644 index 0000000000..81389b712c --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-uses-mtype.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "video-bid", "impid": "test-imp-id", "price": 4.0, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480, "mtype": 2 }, + { "id": "banner-bid", "impid": "test-imp-id", "price": 1.5, "adm": "<div>ad</div>", "crid": "b-1", "w": 300, "h": 250, "mtype": 1 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "video-bid", "impid": "test-imp-id", "price": 4.0, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480, "mtype": 2 }, "type": "video" }, + { "bid": { "id": "banner-bid", "impid": "test-imp-id", "price": 1.5, "adm": "<div>ad</div>", "crid": "b-1", "w": 300, "h": 250, "mtype": 1 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/multi-format-imp-without-mtype-errors.json b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-without-mtype-errors.json new file mode 100644 index 0000000000..312f0f06b2 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/multi-format-imp-without-mtype-errors.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "ambiguous", "impid": "test-imp-id", "price": 2.0, "adm": "<div>?</div>", "crid": "c-1" } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "bid for multi-format imp test-imp-id requires bid.mtype to disambiguate", + "comparison": "literal" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/multi-imp-asymmetry.json b/adapters/eskimi/eskimitest/supplemental/multi-imp-asymmetry.json new file mode 100644 index 0000000000..c712c0783e --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/multi-imp-asymmetry.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "placementId": 625, + "bcat": ["IAB-FROM-IMP-0"], + "bidFloor": 1.0 + } + } + }, + { + "id": "imp-2", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "ext": { + "bidder": { + "placementId": 999, + "bcat": ["IAB-FROM-IMP-1"], + "bidFloor": 2.0, + "bidFloorCur": "EUR" + } + } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "bcat": ["IAB-FROM-IMP-0"], + "imp": [ + { + "id": "imp-1", + "secure": 1, + "bidfloor": 1.0, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "placementId": 625, + "bcat": ["IAB-FROM-IMP-0"], + "bidFloor": 1.0 + } + } + }, + { + "id": "imp-2", + "secure": 1, + "bidfloor": 2.0, + "bidfloorcur": "EUR", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "ext": { + "bidder": { + "placementId": 999, + "bcat": ["IAB-FROM-IMP-1"], + "bidFloor": 2.0, + "bidFloorCur": "EUR" + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["imp-1", "imp-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "imp-1", "price": 1.5, "crid": "c1", "w": 300, "h": 250 }, + { "id": "2", "impid": "imp-2", "price": 2.5, "crid": "c2", "w": 728, "h": 90 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "imp-1", "price": 1.5, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" }, + { "bid": { "id": "2", "impid": "imp-2", "price": 2.5, "crid": "c2", "w": 728, "h": 90 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/multi-imp-invalid-second-dropped.json b/adapters/eskimi/eskimitest/supplemental/multi-imp-invalid-second-dropped.json new file mode 100644 index 0000000000..da98bbb32d --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/multi-imp-invalid-second-dropped.json @@ -0,0 +1,79 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "invalid imp.ext.bidder for imp imp-2:.*", + "comparison": "regex" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-1", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "placementId": 625 + } + } + }, + { + "id": "imp-2", + "banner": { "format": [{ "w": 728, "h": 90 }] }, + "ext": { "bidder": "not-an-object" } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp-1", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { + "bidder": { + "placementId": 625 + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["imp-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "imp-1", "price": 1.5, "crid": "c1", "w": 300, "h": 250, "mtype": 1 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "imp-1", "price": 1.5, "crid": "c1", "w": 300, "h": 250, "mtype": 1 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/no-site-or-app.json b/adapters/eskimi/eskimitest/supplemental/no-site-or-app.json new file mode 100644 index 0000000000..6456b473b8 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/no-site-or-app.json @@ -0,0 +1,19 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "request must contain either site or app", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ] + }, + "httpCalls": [] +} diff --git a/adapters/eskimi/eskimitest/supplemental/pre-set-overrides-not-clobbered.json b/adapters/eskimi/eskimitest/supplemental/pre-set-overrides-not-clobbered.json new file mode 100644 index 0000000000..c0cddb72de --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/pre-set-overrides-not-clobbered.json @@ -0,0 +1,96 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "bcat": ["IAB-EXISTING"], + "badv": ["existing-blocked.com"], + "bapp": ["com.existing.blocked"], + "imp": [ + { + "id": "test-imp-id", + "bidfloor": 5.0, + "bidfloorcur": "USD", + "banner": { + "format": [{ "w": 300, "h": 250 }], + "battr": [3] + }, + "ext": { + "bidder": { + "placementId": 625, + "bcat": ["IAB-FROM-EXT"], + "badv": ["ext-blocked.com"], + "bapp": ["com.ext.blocked"], + "bidFloor": 1.0, + "bidFloorCur": "EUR", + "battr": [1, 2] + } + } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "bcat": ["IAB-EXISTING"], + "badv": ["existing-blocked.com"], + "bapp": ["com.existing.blocked"], + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "bidfloor": 5.0, + "bidfloorcur": "USD", + "banner": { + "format": [{ "w": 300, "h": 250 }], + "battr": [3] + }, + "ext": { + "bidder": { + "placementId": 625, + "bcat": ["IAB-FROM-EXT"], + "badv": ["ext-blocked.com"], + "bapp": ["com.ext.blocked"], + "bidFloor": 1.0, + "bidFloorCur": "EUR", + "battr": [1, 2] + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 6.0, "crid": "c1", "w": 300, "h": 250 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 6.0, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/privacy-signals-pass-through.json b/adapters/eskimi/eskimitest/supplemental/privacy-signals-pass-through.json new file mode 100644 index 0000000000..16f6f440bf --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/privacy-signals-pass-through.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" }, + "user": { + "ext": { + "consent": "CO12345abcdefghijklmnopqrstuvwxyz" + } + }, + "regs": { + "coppa": 1, + "us_privacy": "1YYY", + "gpp": "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA", + "gpp_sid": [7, 8], + "ext": { + "gdpr": 1 + } + }, + "device": { + "lmt": 1, + "dnt": 1 + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + }, + "user": { + "ext": { "consent": "CO12345abcdefghijklmnopqrstuvwxyz" } + }, + "regs": { + "coppa": 1, + "us_privacy": "1YYY", + "gpp": "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA", + "gpp_sid": [7, 8], + "ext": { "gdpr": 1 } + }, + "device": { "lmt": 1, "dnt": 1 } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/response-204.json b/adapters/eskimi/eskimitest/supplemental/response-204.json new file mode 100644 index 0000000000..b82f4f1ff8 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/response-204.json @@ -0,0 +1,41 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/eskimi/eskimitest/supplemental/response-400.json b/adapters/eskimi/eskimitest/supplemental/response-400.json new file mode 100644 index 0000000000..81d636608c --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/response-400.json @@ -0,0 +1,46 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/response-500.json b/adapters/eskimi/eskimitest/supplemental/response-500.json new file mode 100644 index 0000000000..daf7265354 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/response-500.json @@ -0,0 +1,46 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/response-no-cur.json b/adapters/eskimi/eskimitest/supplemental/response-no-cur.json new file mode 100644 index 0000000000..43a8eae814 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/response-no-cur.json @@ -0,0 +1,59 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/schain-pass-through.json b/adapters/eskimi/eskimitest/supplemental/schain-pass-through.json new file mode 100644 index 0000000000..fc3b0d5841 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/schain-pass-through.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" }, + "source": { + "schain": { + "complete": 1, + "ver": "1.0", + "nodes": [ + { "asi": "publisher.com", "sid": "pub-sid-1", "hp": 1 }, + { "asi": "ssp.example", "sid": "ssp-sid-2", "hp": 1 } + ] + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + }, + "source": { + "schain": { + "complete": 1, + "ver": "1.0", + "nodes": [ + { "asi": "publisher.com", "sid": "pub-sid-1", "hp": 1 }, + { "asi": "ssp.example", "sid": "ssp-sid-2", "hp": 1 } + ] + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/site-ext-merge.json b/adapters/eskimi/eskimitest/supplemental/site-ext-merge.json new file mode 100644 index 0000000000..a6cfa15fe3 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/site-ext-merge.json @@ -0,0 +1,71 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { + "amp": 0, + "data": { "category": "news" } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { + "amp": 0, + "data": { "category": "news" }, + "placementId": 625 + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 1.0, "crid": "c1", "w": 300, "h": 250 }, "type": "banner" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/unmatched-bid-impid.json b/adapters/eskimi/eskimitest/supplemental/unmatched-bid-impid.json new file mode 100644 index 0000000000..0675afde99 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/unmatched-bid-impid.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "b1", "impid": "unknown-imp", "price": 1.0, "crid": "c1" } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unable to resolve media type for impression unknown-imp", + "comparison": "literal" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/unsupported-bid-media-type.json b/adapters/eskimi/eskimitest/supplemental/unsupported-bid-media-type.json new file mode 100644 index 0000000000..4fd0906dfd --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/unsupported-bid-media-type.json @@ -0,0 +1,75 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + }, + { + "id": "native-imp", + "native": { "request": "{}" }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "ext": { "bidder": { "placementId": 625 } } + }, + { + "id": "native-imp", + "secure": 1, + "native": { "request": "{}" }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id", "native-imp"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "native-imp", "price": 1.0, "crid": "c1" } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported media type for impression native-imp (banner and video only)", + "comparison": "literal" + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/video-no-mtype-inferred.json b/adapters/eskimi/eskimitest/supplemental/video-no-mtype-inferred.json new file mode 100644 index 0000000000..28200c899c --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/video-no-mtype-inferred.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "protocols": [2, 3, 5, 6, 7, 8] + }, + "ext": { "bidder": { "placementId": 625 } } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { "id": "1", "impid": "test-imp-id", "price": 3.0, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480 } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { "bid": { "id": "1", "impid": "test-imp-id", "price": 3.0, "adm": "<VAST/>", "crid": "v-1", "w": 640, "h": 480 }, "type": "video" } + ] + } + ] +} diff --git a/adapters/eskimi/eskimitest/supplemental/video-outstream-web.json b/adapters/eskimi/eskimitest/supplemental/video-outstream-web.json new file mode 100644 index 0000000000..0d6ab19885 --- /dev/null +++ b/adapters/eskimi/eskimitest/supplemental/video-outstream-web.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 4 + }, + "ext": { + "bidder": { + "placementId": 625, + "battr": [13, 14] + } + } + } + ], + "site": { "id": "271", "domain": "display.eskimi-creatives.com" } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ittr.eskimi.com/prebidjs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "secure": 1, + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360, + "protocols": [2, 3, 5, 6, 7, 8], + "plcmt": 4, + "battr": [13, 14] + }, + "ext": { + "bidder": { + "placementId": 625, + "battr": [13, 14] + } + } + } + ], + "site": { + "id": "271", + "domain": "display.eskimi-creatives.com", + "ext": { "placementId": 625 } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "eskimi", + "bid": [ + { + "id": "1", + "impid": "test-imp-id", + "price": 3.5, + "adm": "<VAST version=\"4.0\"></VAST>", + "crid": "outstream-1", + "w": 640, + "h": 360, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 3.5, + "adm": "<VAST version=\"4.0\"></VAST>", + "crid": "outstream-1", + "w": 640, + "h": 360, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/eskimi/params_test.go b/adapters/eskimi/params_test.go new file mode 100644 index 0000000000..a2c559e90e --- /dev/null +++ b/adapters/eskimi/params_test.go @@ -0,0 +1,56 @@ +package eskimi + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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 schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderEskimi, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderEskimi, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"placementId":625}`, + `{"placementId":625,"bidFloor":0.5,"bidFloorCur":"USD"}`, + `{"placementId":625,"bcat":["IAB1"],"badv":["bad.com"],"bapp":["com.bad.app"]}`, + `{"placementId":625,"battr":[1,2,17]}`, +} + +var invalidParams = []string{ + ``, + `null`, + `{}`, + `{"placementId":"625"}`, + `{"placementId":625.5}`, + `{"placementId":0}`, + `{"placementId":-1}`, + `{"bidFloor":0.5}`, + `{"placementId":625,"bcat":"IAB1"}`, + `{"placementId":625,"battr":[0]}`, + `{"placementId":625,"battr":[18]}`, + `{"placementId":625,"unknownField":"foo"}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 8e6e0cd061..9f02d8bdef 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -104,6 +104,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/eplanning" "github.com/prebid/prebid-server/v4/adapters/epom" "github.com/prebid/prebid-server/v4/adapters/escalax" + "github.com/prebid/prebid-server/v4/adapters/eskimi" "github.com/prebid/prebid-server/v4/adapters/exco" "github.com/prebid/prebid-server/v4/adapters/feedad" "github.com/prebid/prebid-server/v4/adapters/flatads" @@ -377,6 +378,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEPlanning: eplanning.Builder, openrtb_ext.BidderEpom: epom.Builder, openrtb_ext.BidderEscalax: escalax.Builder, + openrtb_ext.BidderEskimi: eskimi.Builder, openrtb_ext.BidderExco: exco.Builder, openrtb_ext.BidderEVolution: evolution.Builder, openrtb_ext.BidderFeedAd: feedad.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 0c8e92672c..5b2dd8418f 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -120,6 +120,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderEPlanning, BidderEpom, BidderEscalax, + BidderEskimi, BidderEVolution, BidderExco, BidderFeedAd, @@ -500,6 +501,7 @@ const ( BidderEPlanning BidderName = "eplanning" BidderEpom BidderName = "epom" BidderEscalax BidderName = "escalax" + BidderEskimi BidderName = "eskimi" BidderExco BidderName = "exco" BidderEVolution BidderName = "e_volution" BidderFeedAd BidderName = "feedad" diff --git a/openrtb_ext/imp_eskimi.go b/openrtb_ext/imp_eskimi.go new file mode 100644 index 0000000000..cf6922c21d --- /dev/null +++ b/openrtb_ext/imp_eskimi.go @@ -0,0 +1,14 @@ +package openrtb_ext + +// ExtImpEskimi defines the contract for bidrequest.imp[i].ext.prebid.bidder.eskimi. +// COPPA and test flags are handled by PBS core via request.regs.coppa / request.test; +// they are not duplicated as bidder params. +type ExtImpEskimi struct { + PlacementID int64 `json:"placementId"` + BidFloor float64 `json:"bidFloor,omitempty"` + BidFloorCur string `json:"bidFloorCur,omitempty"` + Bcat []string `json:"bcat,omitempty"` + Badv []string `json:"badv,omitempty"` + Bapp []string `json:"bapp,omitempty"` + Battr []int64 `json:"battr,omitempty"` +} diff --git a/static/bidder-info/eskimi.yaml b/static/bidder-info/eskimi.yaml new file mode 100644 index 0000000000..c3e02c49eb --- /dev/null +++ b/static/bidder-info/eskimi.yaml @@ -0,0 +1,21 @@ +endpoint: "https://ittr.eskimi.com/prebidjs" +maintainer: + email: prebid@eskimi.com +gvlVendorID: 814 +modifyingVastXmlAllowed: false +openrtb: + version: 2.6 + gpp-supported: true +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + redirect: + url: "https://ittpx.eskimi.com/sync?sp_id=137&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&dest={{.RedirectURL}}" + userMacro: "${USER_ID}" diff --git a/static/bidder-params/eskimi.json b/static/bidder-params/eskimi.json new file mode 100644 index 0000000000..a69a8da81e --- /dev/null +++ b/static/bidder-params/eskimi.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Eskimi Adapter Params", + "description": "A schema which validates params accepted by the Eskimi adapter", + "type": "object", + "additionalProperties": false, + "properties": { + "placementId": { + "type": "integer", + "minimum": 1, + "description": "The Eskimi placement ID" + }, + "bidFloor": { + "type": "number", + "minimum": 0, + "description": "The minimum bid floor (USD unless bidFloorCur is set)" + }, + "bidFloorCur": { + "type": "string", + "description": "The currency of the bid floor" + }, + "bcat": { + "type": "array", + "items": { "type": "string" }, + "description": "Blocked IAB advertiser categories" + }, + "badv": { + "type": "array", + "items": { "type": "string" }, + "description": "Blocked advertiser domains" + }, + "bapp": { + "type": "array", + "items": { "type": "string" }, + "description": "Blocked app bundles" + }, + "battr": { + "type": "array", + "items": { "type": "integer", "minimum": 1, "maximum": 17 }, + "description": "Blocked creative attributes (OpenRTB List 5.3)" + } + }, + "required": ["placementId"] +} From a5002538f1f3dab9ee2b2e13cd84924d2e243ae5 Mon Sep 17 00:00:00 2001 From: Patel Manan Rajeshkumar <67188104+MananRPatel@users.noreply.github.com> Date: Tue, 4 Aug 2026 21:15:43 +0530 Subject: [PATCH 250/272] Yahoo Ads: Migrate to OpenRTB 2.6 (#4803) Co-authored-by: MananRPatel <prebid-tech-team@yahooinc.com> --- adapters/yahooAds/promote_regs_test.go | 256 ++++++++++++++++++ adapters/yahooAds/yahooAds.go | 90 ++++-- .../exemplary/simple-app-banner.json | 2 +- .../yahooAdstest/exemplary/simple-banner.json | 2 +- .../yahooAdstest/exemplary/simple-video.json | 2 +- .../non-supported-requests-bids-ignored.json | 2 +- .../server-response-wrong-impid.json | 2 +- ...le-banner-gpp-ext-duplicate-stripped.json} | 6 +- .../simple-banner-gpp-ext-promoted.json | 148 ++++++++++ .../supplemental/simple-banner-gpp.json | 8 +- ...nner-ignore-width-when-height-missing.json | 2 +- .../simple-banner-two-imps-shared-regs.json | 235 ++++++++++++++++ static/bidder-info/yahooAds.yaml | 2 + 13 files changed, 719 insertions(+), 38 deletions(-) create mode 100644 adapters/yahooAds/promote_regs_test.go rename adapters/yahooAds/yahooAdstest/supplemental/{simple-banner-gpp-overwrite.json => simple-banner-gpp-ext-duplicate-stripped.json} (97%) create mode 100644 adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-promoted.json create mode 100644 adapters/yahooAds/yahooAdstest/supplemental/simple-banner-two-imps-shared-regs.json diff --git a/adapters/yahooAds/promote_regs_test.go b/adapters/yahooAds/promote_regs_test.go new file mode 100644 index 0000000000..6ed9a428a7 --- /dev/null +++ b/adapters/yahooAds/promote_regs_test.go @@ -0,0 +1,256 @@ +package yahooAds + +import ( + "encoding/json" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "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/openrtb_ext" +) + +func regsExt(j string) *openrtb2.Regs { + return &openrtb2.Regs{Ext: []byte(j)} +} + +// TestPromoteRegsExtTo26 exercises the regs.ext promotion in isolation; the +// JSON fixtures cover the same logic end-to-end through MakeRequests. +func TestPromoteRegsExtTo26(t *testing.T) { + tests := []struct { + name string + inRegs *openrtb2.Regs + wantGPP string + wantGPPSID []int8 + wantExt string // expected regs.ext JSON when it should remain + wantNoExt bool // expect regs.ext to be empty/nil after the call + wantRegsUnchanged bool + wantWarning bool // expect one errortypes.Warning + }{ + { + name: "nil_regs", + inRegs: nil, + wantRegsUnchanged: true, + }, + { + name: "regs_without_ext", + inRegs: &openrtb2.Regs{}, + wantNoExt: true, + wantRegsUnchanged: true, + }, + { + name: "regs_with_empty_ext_bytes", + inRegs: &openrtb2.Regs{Ext: []byte{}}, + wantNoExt: true, + wantRegsUnchanged: true, + }, + { + name: "regs_with_empty_object_ext", + inRegs: regsExt(`{}`), + wantExt: `{}`, + wantRegsUnchanged: true, + }, + { + name: "regs_ext_array_not_object", + inRegs: regsExt(`[1,2,3]`), + wantExt: `[1,2,3]`, + wantRegsUnchanged: true, + wantWarning: true, + }, + { + name: "regs_ext_number_not_object", + inRegs: regsExt(`42`), + wantExt: `42`, + wantRegsUnchanged: true, + wantWarning: true, + }, + { + name: "promote_gpp_only", + inRegs: regsExt(`{"gpp":"DBA"}`), + wantGPP: "DBA", + wantNoExt: true, + }, + { + name: "promote_gpp_sid_only", + inRegs: regsExt(`{"gpp_sid":[6,7]}`), + wantGPPSID: []int8{6, 7}, + wantNoExt: true, + }, + { + name: "promote_both_gpp_fields_together", + inRegs: regsExt(`{"gpp":"X","gpp_sid":[6]}`), + wantGPP: "X", + wantGPPSID: []int8{6}, + wantNoExt: true, + }, + { + name: "promote_with_unrelated_sibling_gpc", + inRegs: regsExt(`{"gpp":"X","gpp_sid":[6],"gpc":"1"}`), + wantGPP: "X", + wantGPPSID: []int8{6}, + wantExt: `{"gpc":"1"}`, + }, + { + name: "promote_gpp_keep_dsa_object_in_ext", + inRegs: regsExt(`{"gpp":"X","dsa":{"dsarequired":1}}`), + wantGPP: "X", + wantExt: `{"dsa":{"dsarequired":1}}`, + }, + { + name: "wrong_type_gpp_number_stays_in_ext", + inRegs: regsExt(`{"gpp":123,"gpp_sid":[6]}`), + wantGPPSID: []int8{6}, + wantExt: `{"gpp":123}`, + }, + { + name: "wrong_type_gpp_sid_string_stays_in_ext", + inRegs: regsExt(`{"gpp":"X","gpp_sid":"oops"}`), + wantGPP: "X", + wantExt: `{"gpp_sid":"oops"}`, + }, + { + name: "wrong_type_only_regs_untouched", + inRegs: regsExt(`{"gpp":123}`), + wantExt: `{"gpp":123}`, + wantRegsUnchanged: true, + }, + { + name: "promote_gpp_empty_string_consumed", + inRegs: regsExt(`{"gpp":""}`), + wantGPP: "", + wantNoExt: true, + }, + { + name: "promote_gpp_sid_empty_array", + inRegs: regsExt(`{"gpp_sid":[]}`), + wantGPPSID: []int8{}, + wantNoExt: true, + }, + { + name: "top_gpp_already_set_ext_duplicate_stripped", + inRegs: &openrtb2.Regs{ + GPP: "EXISTING", + Ext: []byte(`{"gpp":"EXT_VALUE"}`), + }, + wantGPP: "EXISTING", + wantNoExt: true, + }, + { + name: "top_gpp_sid_already_set_ext_duplicate_stripped", + inRegs: &openrtb2.Regs{ + GPPSID: []int8{1, 2}, + Ext: []byte(`{"gpp_sid":[6]}`), + }, + wantGPPSID: []int8{1, 2}, + wantNoExt: true, + }, + { + name: "top_gpp_set_duplicate_stripped_sibling_kept", + inRegs: &openrtb2.Regs{ + GPP: "KEEP", + Ext: []byte(`{"gpp":"stale","gpc":"1"}`), + }, + wantGPP: "KEEP", + wantExt: `{"gpc":"1"}`, + }, + { + name: "top_gpp_set_wrong_typed_duplicate_also_stripped", + inRegs: &openrtb2.Regs{ + GPP: "KEEP", + Ext: []byte(`{"gpp":123}`), + }, + wantGPP: "KEEP", + wantNoExt: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, warnings := promoteRegsExtTo26(tt.inRegs) + + if tt.wantWarning { + require.Len(t, warnings, 1) + assert.IsType(t, &errortypes.Warning{}, warnings[0]) + } else { + assert.Empty(t, warnings) + } + + if tt.wantRegsUnchanged { + assert.Same(t, tt.inRegs, got, "regs pointer should NOT change for no-op input") + } else { + assert.NotSame(t, tt.inRegs, got, "regs should be swapped to a fresh copy after promotion") + } + + if got == nil { + return + } + + assert.Equal(t, tt.wantGPP, got.GPP, "regs.gpp") + assert.Equal(t, tt.wantGPPSID, got.GPPSID, "regs.gpp_sid") + + switch { + case tt.wantNoExt: + assert.Empty(t, got.Ext, "regs.ext should be empty/nil") + case tt.wantExt != "": + var gotExt, wantExt any + require.NoError(t, json.Unmarshal(got.Ext, &gotExt), "regs.ext should be valid JSON") + require.NoError(t, json.Unmarshal([]byte(tt.wantExt), &wantExt)) + assert.Equal(t, wantExt, gotExt, "regs.ext content") + default: + t.Fatal("test case must set wantNoExt or wantExt") + } + }) + } +} + +// The original *Regs must never be mutated: other adapters and per-impression +// copies must keep seeing the publisher's original request shape. +func TestPromoteRegsExtTo26_DoesNotMutateOriginalRegs(t *testing.T) { + originalExt := []byte(`{"gpp":"X","gpp_sid":[6],"gpc":"1"}`) + originalRegs := &openrtb2.Regs{Ext: append([]byte(nil), originalExt...)} + + beforeGPP := originalRegs.GPP + beforeGPPSID := append([]int8(nil), originalRegs.GPPSID...) + beforeExt := append([]byte(nil), originalRegs.Ext...) + + got, warnings := promoteRegsExtTo26(originalRegs) + + assert.Empty(t, warnings) + assert.Equal(t, beforeGPP, originalRegs.GPP, "original Regs.GPP was mutated") + assert.Equal(t, beforeGPPSID, originalRegs.GPPSID, "original Regs.GPPSID was mutated") + assert.Equal(t, beforeExt, []byte(originalRegs.Ext), "original Regs.Ext bytes were mutated") + + assert.NotSame(t, originalRegs, got, "promoted regs should be a fresh copy") + assert.Equal(t, "X", got.GPP) + assert.Equal(t, []int8{6}, got.GPPSID) + assert.JSONEq(t, `{"gpc":"1"}`, string(got.Ext), "gpc stays in ext") +} + +// A regs.ext warning must not drop the impression: the bid request still goes +// out, with regs.ext passed through untouched. +func TestMakeRequestsMalformedRegsExtWarning(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderYahooAds, config.Adapter{}, config.Server{}) + require.NoError(t, buildErr) + + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{{ + ID: "test-imp-id", + Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}, + Ext: []byte(`{"bidder":{"dcn":"dcn1","pos":"pos2"}}`), + }}, + Site: &openrtb2.Site{ID: "test-site-id"}, + Regs: &openrtb2.Regs{Ext: []byte(`[1,2,3]`)}, + } + + reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + require.Len(t, errs, 1) + assert.IsType(t, &errortypes.Warning{}, errs[0]) + require.Len(t, reqs, 1, "impression must not be dropped on a regs.ext warning") + assert.Contains(t, string(reqs[0].Body), `"ext":[1,2,3]`, "regs.ext should pass through untouched") +} diff --git a/adapters/yahooAds/yahooAds.go b/adapters/yahooAds/yahooAds.go index 1be27dc3c5..18c94aa985 100644 --- a/adapters/yahooAds/yahooAds.go +++ b/adapters/yahooAds/yahooAds.go @@ -26,12 +26,17 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") - headers.Add("x-openrtb-version", "2.5") + headers.Add("x-openrtb-version", "2.6") if request.Device != nil && request.Device.UA != "" { headers.Set("User-Agent", request.Device.UA) } + // Regs depends only on request-level data, so promote once and reuse the + // result for every per-impression copy. + promotedRegs, regsWarnings := promoteRegsExtTo26(request.Regs) + errors = append(errors, regsWarnings...) + for idx, imp := range request.Imp { var bidderExt adapters.ExtImpBidder err := jsonutil.Unmarshal(imp.Ext, &bidderExt) @@ -57,6 +62,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E // each split request is only associated to a single impression reqCopy := *request reqCopy.Imp = []openrtb2.Imp{imp} + reqCopy.Regs = promotedRegs if request.Site != nil { siteCopy := *request.Site @@ -172,37 +178,73 @@ func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb } } - if request.Regs != nil && request.Regs.GPP != "" { - requestRegs := *request.Regs - if requestRegs.Ext == nil { - requestRegs.Ext = json.RawMessage("{}") - } - var regsExt map[string]json.RawMessage - err := jsonutil.Unmarshal(requestRegs.Ext, ®sExt) - if err != nil { - return err - } - regsExt["gpp"], err = json.Marshal(&requestRegs.GPP) - if err != nil { - return fmt.Errorf("failed to marshal requestRegs.GPP: %v", err) + return nil +} + +// promoteRegsExtTo26 moves regs.ext.{gpp, gpp_sid} to their top-level fields +// when the publisher sent them in ext and the top-level field is empty. +// When the top-level field is already set, the ext duplicate is removed so +// only the authoritative top-level value ships. A regs.ext that is not a JSON +// object is passed through untouched with a non-fatal warning. +func promoteRegsExtTo26(regs *openrtb2.Regs) (*openrtb2.Regs, []error) { + if regs == nil || len(regs.Ext) == 0 { + return regs, nil + } + + var regsExt map[string]json.RawMessage + if err := jsonutil.Unmarshal(regs.Ext, ®sExt); err != nil { + return regs, []error{&errortypes.Warning{ + Message: "regs.ext is not a JSON object; skipped OpenRTB 2.6 regs promotion", + }} + } + + regsCopy := *regs + modified := false + + if raw, ok := regsExt["gpp"]; ok { + if regsCopy.GPP == "" { + var v string + if err := jsonutil.Unmarshal(raw, &v); err == nil { + regsCopy.GPP = v + delete(regsExt, "gpp") + modified = true + } + } else { + delete(regsExt, "gpp") + modified = true } - if requestRegs.GPPSID != nil { - regsExt["gpp_sid"], err = json.Marshal(&requestRegs.GPPSID) - if err != nil { - return err + } + + if raw, ok := regsExt["gpp_sid"]; ok { + if len(regsCopy.GPPSID) == 0 { + var v []int8 + if err := jsonutil.Unmarshal(raw, &v); err == nil { + regsCopy.GPPSID = v + delete(regsExt, "gpp_sid") + modified = true } + } else { + delete(regsExt, "gpp_sid") + modified = true } + } + + if !modified { + return regs, nil + } - requestRegs.Ext, err = json.Marshal(®sExt) + if len(regsExt) == 0 { + regsCopy.Ext = nil + } else { + // stdlib json.Marshal is used because it writes a nil RawMessage as null. + newExt, err := json.Marshal(regsExt) if err != nil { - return err + return regs, nil } - requestRegs.GPP = "" - requestRegs.GPPSID = nil - request.Regs = &requestRegs + regsCopy.Ext = newExt } - return nil + return ®sCopy, nil } func validateBanner(banner *openrtb2.Banner) error { diff --git a/adapters/yahooAds/yahooAdstest/exemplary/simple-app-banner.json b/adapters/yahooAds/yahooAdstest/exemplary/simple-app-banner.json index 6b61861d9b..2b2a451cb1 100644 --- a/adapters/yahooAds/yahooAdstest/exemplary/simple-app-banner.json +++ b/adapters/yahooAds/yahooAdstest/exemplary/simple-app-banner.json @@ -39,7 +39,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/exemplary/simple-banner.json b/adapters/yahooAds/yahooAdstest/exemplary/simple-banner.json index 3d0b4a37b0..8253ac8853 100644 --- a/adapters/yahooAds/yahooAdstest/exemplary/simple-banner.json +++ b/adapters/yahooAds/yahooAdstest/exemplary/simple-banner.json @@ -39,7 +39,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/exemplary/simple-video.json b/adapters/yahooAds/yahooAdstest/exemplary/simple-video.json index 9f9d188d00..e30a70df25 100644 --- a/adapters/yahooAds/yahooAdstest/exemplary/simple-video.json +++ b/adapters/yahooAds/yahooAdstest/exemplary/simple-video.json @@ -47,7 +47,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/supplemental/non-supported-requests-bids-ignored.json b/adapters/yahooAds/yahooAdstest/supplemental/non-supported-requests-bids-ignored.json index 5e0820761d..b5e83649f0 100644 --- a/adapters/yahooAds/yahooAdstest/supplemental/non-supported-requests-bids-ignored.json +++ b/adapters/yahooAds/yahooAdstest/supplemental/non-supported-requests-bids-ignored.json @@ -38,7 +38,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/supplemental/server-response-wrong-impid.json b/adapters/yahooAds/yahooAdstest/supplemental/server-response-wrong-impid.json index a831dba64b..c5f3f47c01 100644 --- a/adapters/yahooAds/yahooAdstest/supplemental/server-response-wrong-impid.json +++ b/adapters/yahooAds/yahooAdstest/supplemental/server-response-wrong-impid.json @@ -38,7 +38,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-overwrite.json b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-duplicate-stripped.json similarity index 97% rename from adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-overwrite.json rename to adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-duplicate-stripped.json index 950796692a..bcd41b7e56 100644 --- a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-overwrite.json +++ b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-duplicate-stripped.json @@ -47,7 +47,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", @@ -78,9 +78,9 @@ "id": "dcn1" }, "regs": { + "gpp": "header~1YNN", + "gpp_sid": [6], "ext": { - "gpp": "header~1YNN", - "gpp_sid": [6], "param1": "val1" } } diff --git a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-promoted.json b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-promoted.json new file mode 100644 index 0000000000..cd29e6cde9 --- /dev/null +++ b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp-ext-promoted.json @@ -0,0 +1,148 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "123", + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos2" + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "site": { + "id": "test-site-id" + }, + "regs": { + "ext": { + "gpp": "header~1YNN", + "gpp_sid": [ + 6 + ], + "gpc": "1" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "", + "body": { + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "pos2", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ], + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos2" + } + } + } + ], + "site": { + "id": "dcn1" + }, + "regs": { + "gpp": "header~1YNN", + "gpp_sid": [ + 6 + ], + "ext": { + "gpc": "1" + } + } + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "yahooAds", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp.json b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp.json index 73012144fb..d8b9c22a32 100644 --- a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp.json +++ b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-gpp.json @@ -43,7 +43,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", @@ -74,10 +74,8 @@ "id": "dcn1" }, "regs": { - "ext": { - "gpp": "header~1YNN", - "gpp_sid": [6] - } + "gpp": "header~1YNN", + "gpp_sid": [6] } }, "impIDs":["test-imp-id"] diff --git a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-ignore-width-when-height-missing.json b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-ignore-width-when-height-missing.json index 513e37f9f1..92b575369f 100644 --- a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-ignore-width-when-height-missing.json +++ b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-ignore-width-when-height-missing.json @@ -40,7 +40,7 @@ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "", diff --git a/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-two-imps-shared-regs.json b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-two-imps-shared-regs.json new file mode 100644 index 0000000000..eddd62ee93 --- /dev/null +++ b/adapters/yahooAds/yahooAdstest/supplemental/simple-banner-two-imps-shared-regs.json @@ -0,0 +1,235 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-1", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos2" + } + } + }, + { + "id": "test-imp-2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos3" + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "site": { + "id": "test-site-id" + }, + "regs": { + "ext": { + "gpp": "header~1YNN", + "gpp_sid": [6], + "gpc": "1" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "", + "body": { + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-1", + "tagid": "pos2", + "banner": { + "format": [{"w": 300, "h": 250}], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos2" + } + } + } + ], + "site": { + "id": "dcn1" + }, + "regs": { + "gpp": "header~1YNN", + "gpp_sid": [6], + "ext": { + "gpc": "1" + } + } + }, + "impIDs": ["test-imp-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "yahooAds", + "bid": [{ + "id": "bid-1", + "impid": "test-imp-1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 250, + "w": 300 + }] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Openrtb-Version": [ + "2.6" + ] + }, + "uri": "", + "body": { + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-2", + "tagid": "pos3", + "banner": { + "format": [{"w": 728, "h": 90}], + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "dcn": "dcn1", + "pos": "pos3" + } + } + } + ], + "site": { + "id": "dcn1" + }, + "regs": { + "gpp": "header~1YNN", + "gpp_sid": [6], + "ext": { + "gpc": "1" + } + } + }, + "impIDs": ["test-imp-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "yahooAds", + "bid": [{ + "id": "bid-2", + "impid": "test-imp-2", + "price": 0.750000, + "adm": "some-test-ad-2", + "crid": "crid_11", + "h": 90, + "w": 728 + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 300, + "h": 250 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-2", + "impid": "test-imp-2", + "price": 0.75, + "adm": "some-test-ad-2", + "crid": "crid_11", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/static/bidder-info/yahooAds.yaml b/static/bidder-info/yahooAds.yaml index c53d1b14e0..2d86a0f27a 100644 --- a/static/bidder-info/yahooAds.yaml +++ b/static/bidder-info/yahooAds.yaml @@ -2,6 +2,8 @@ endpoint: "https://s2shb.ssp.yahoo.com/admax/bid/partners/PBS" maintainer: email: "prebid-tech-team@yahooinc.com" gvlVendorID: 25 +openrtb: + version: "2.6" capabilities: app: mediaTypes: From 68d1b28c30e1918d6a3bfee03768b8e146f4b1dc Mon Sep 17 00:00:00 2001 From: Eugene Dorfman <eugene.dorfman@gmail.com> Date: Thu, 6 Aug 2026 17:08:21 +0200 Subject: [PATCH 251/272] 51Degrees: Extend device detection module with new fields (#4740) Co-authored-by: legendko <legend.ko@hotmail.com> --- .../devicedetection/device_detector.go | 2 ++ .../devicedetection/device_info_extractor.go | 6 ++++++ .../device_info_extractor_test.go | 4 ++++ .../hook_raw_auction_request.go | 10 ++++++++++ .../fiftyonedegrees/devicedetection/models.go | 2 ++ .../devicedetection/module_test.go | 18 ++++++++++++------ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/modules/fiftyonedegrees/devicedetection/device_detector.go b/modules/fiftyonedegrees/devicedetection/device_detector.go index 9f66c64eea..73c2f46601 100644 --- a/modules/fiftyonedegrees/devicedetection/device_detector.go +++ b/modules/fiftyonedegrees/devicedetection/device_detector.go @@ -68,6 +68,8 @@ func buildEngineOptions(moduleConfig *config, configHash *dd.ConfigHash) []onpre "HardwareModel", "HardwareFamily", "HardwareModelVariants", + "HardwareNamePrefix", + "HardwareNameVersion", "ScreenInchesHeight", "IsCrawler", }), diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go index e3c4bca69d..ef3aeef360 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go @@ -44,6 +44,8 @@ const ( deviceInfoHardwareFamily deviceInfoProperty = "HardwareFamily" deviceInfoHardwareModelVariants deviceInfoProperty = "HardwareModelVariants" deviceInfoScreenInchesHeight deviceInfoProperty = "ScreenInchesHeight" + deviceInfoHardwareNamePrefix deviceInfoProperty = "HardwareNamePrefix" + deviceInfoHardwareNameVersion deviceInfoProperty = "HardwareNameVersion" ) func (x deviceInfoExtractor) extract(results Results, ua string) (*deviceInfo, error) { @@ -69,6 +71,8 @@ func (x deviceInfoExtractor) extract(results Results, ua string) (*deviceInfo, e hardwareFamily := x.getValue(results, deviceInfoHardwareFamily) hardwareModelVariants := x.getValue(results, deviceInfoHardwareModelVariants) screenInchedHeight, _ := strconv.ParseFloat(x.getValue(results, deviceInfoScreenInchesHeight), 10) + hardwareNamePrefix := x.getValue(results, deviceInfoHardwareNamePrefix) + hardwareNameVersion := x.getValue(results, deviceInfoHardwareNameVersion) p := &deviceInfo{ HardwareVendor: hardwareVendor, @@ -90,6 +94,8 @@ func (x deviceInfoExtractor) extract(results Results, ua string) (*deviceInfo, e HardwareModel: hardwareModel, HardwareFamily: hardwareFamily, HardwareModelVariants: hardwareModelVariants, + HardwareNamePrefix: hardwareNamePrefix, + HardwareNameVersion: hardwareNameVersion, ScreenInchesHeight: screenInchedHeight, } diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go index 23bee8a5d5..481c93d45f 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor_test.go @@ -107,6 +107,8 @@ func mockValues(results *ResultsHashMock) { mockValue(results, "HardwareModel", "Macbook") mockValue(results, "HardwareFamily", "Macbook") mockValue(results, "HardwareModelVariants", "Macbook") + mockValue(results, "HardwareNamePrefix", "Macbook") + mockValue(results, "HardwareNameVersion", "Pro") mockValue(results, "ScreenInchesHeight", "12") } @@ -124,6 +126,8 @@ func assertDeviceInfo(t *testing.T, deviceInfo *deviceInfo) { assert.Equal(t, deviceInfo.PixelRatio, float64(223)) assert.Equal(t, deviceInfo.Javascript, true) assert.Equal(t, deviceInfo.GeoLocation, true) + assert.Equal(t, deviceInfo.HardwareNamePrefix, "Macbook") + assert.Equal(t, deviceInfo.HardwareNameVersion, "Pro") } func mockValue(results *ResultsHashMock, name string, value string) { diff --git a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go index 9492b4cb08..1bf1aa8203 100644 --- a/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go +++ b/modules/fiftyonedegrees/devicedetection/hook_raw_auction_request.go @@ -116,6 +116,10 @@ func setMissingFields(deviceObj map[string]any, fiftyOneDd *deviceInfo) map[stri return val }, "model": func() any { + if fiftyOneDd.HardwareNamePrefix != "" && fiftyOneDd.HardwareNamePrefix != ddUnknown { + return fiftyOneDd.HardwareNamePrefix + } + // Fallback: HardwareModel → HardwareName newVal := fiftyOneDd.HardwareModel if newVal == ddUnknown { newVal = fiftyOneDd.HardwareName @@ -125,6 +129,12 @@ func setMissingFields(deviceObj map[string]any, fiftyOneDd *deviceInfo) map[stri } return nil }, + "hwv": func() any { + if fiftyOneDd.HardwareNameVersion != "" && fiftyOneDd.HardwareNameVersion != ddUnknown { + return fiftyOneDd.HardwareNameVersion + } + return nil + }, "ppi": func() any { if fiftyOneDd.ScreenPixelsHeight > 0 && fiftyOneDd.ScreenInchesHeight > 0 { ppi := float64(fiftyOneDd.ScreenPixelsHeight) / fiftyOneDd.ScreenInchesHeight diff --git a/modules/fiftyonedegrees/devicedetection/models.go b/modules/fiftyonedegrees/devicedetection/models.go index ffa9887235..6afb4ed038 100644 --- a/modules/fiftyonedegrees/devicedetection/models.go +++ b/modules/fiftyonedegrees/devicedetection/models.go @@ -62,6 +62,8 @@ type deviceInfo struct { HardwareFamily string HardwareModel string HardwareModelVariants string + HardwareNamePrefix string + HardwareNameVersion string UserAgent string DeviceId string ScreenInchesHeight float64 diff --git a/modules/fiftyonedegrees/devicedetection/module_test.go b/modules/fiftyonedegrees/devicedetection/module_test.go index 7f757cd42d..32968515fc 100644 --- a/modules/fiftyonedegrees/devicedetection/module_test.go +++ b/modules/fiftyonedegrees/devicedetection/module_test.go @@ -253,7 +253,7 @@ func TestHandleRawAuctionHookEnrichment(t *testing.T) { deviceDetectorM.On("getDeviceInfo", mock.Anything, mock.Anything).Return( &deviceInfo{ HardwareVendor: "Apple", - HardwareName: "Macbook", + HardwareName: "Macbook Pro", DeviceType: "device", PlatformVendor: "Apple", PlatformName: "MacOs", @@ -269,6 +269,8 @@ func TestHandleRawAuctionHookEnrichment(t *testing.T) { HardwareFamily: "Macbook", HardwareModel: "Macbook", HardwareModelVariants: "Macbook", + HardwareNamePrefix: "Macbook", + HardwareNameVersion: "Pro", UserAgent: "ua", DeviceId: "", }, @@ -402,7 +404,7 @@ func TestHandleRawAuctionHookEnrichment(t *testing.T) { "architecture": "arm", "model": "" } - ,"devicetype":2,"ua":"ua","make":"Apple","model":"Macbook","os":"MacOs","osv":"14","h":1080,"w":1024,"pxratio":223,"js":1,"geoFetch":1} + ,"devicetype":2,"ua":"ua","make":"Apple","model":"Macbook","hwv":"Pro","os":"MacOs","osv":"14","h":1080,"w":1024,"pxratio":223,"js":1,"geoFetch":1} }`) var deviceDetectorErrM mockDeviceDetector @@ -455,7 +457,7 @@ func TestHandleRawAuctionHookEnrichmentWithErrors(t *testing.T) { mockDeviceDetector.On("getDeviceInfo", mock.Anything, mock.Anything).Return( &deviceInfo{ HardwareVendor: "Apple", - HardwareName: "Macbook", + HardwareName: "Macbook Pro", DeviceType: "device", PlatformVendor: "Apple", PlatformName: "MacOs", @@ -471,6 +473,8 @@ func TestHandleRawAuctionHookEnrichmentWithErrors(t *testing.T) { HardwareFamily: "Macbook", HardwareModel: "Macbook", HardwareModelVariants: "Macbook", + HardwareNamePrefix: "Macbook", + HardwareNameVersion: "Pro", UserAgent: "ua", DeviceId: "", ScreenInchesHeight: 7, @@ -501,7 +505,7 @@ func TestHandleRawAuctionHookEnrichmentWithErrors(t *testing.T) { mutationResult, err := mutation.Apply(hookstage.RawAuctionRequestPayload(`{"device":{}}`)) assert.NoError(t, err) - require.JSONEq(t, string(mutationResult), `{"device":{"devicetype":2,"ua":"ua","make":"Apple","model":"Macbook","os":"MacOs","osv":"14","h":1080,"w":1024,"pxratio":223,"js":1,"geoFetch":1,"ppi":154,"ext":{"fiftyonedegrees_deviceId":""}}}`) + require.JSONEq(t, string(mutationResult), `{"device":{"devicetype":2,"ua":"ua","make":"Apple","model":"Macbook","hwv":"Pro","os":"MacOs","osv":"14","h":1080,"w":1024,"pxratio":223,"js":1,"geoFetch":1,"ppi":154,"ext":{"fiftyonedegrees_deviceId":""}}}`) } func TestConfigHashFromConfig(t *testing.T) { @@ -634,7 +638,7 @@ func TestBuilderHandleDeviceDetectorError(t *testing.T) { func TestHydrateFields(t *testing.T) { deviceInfo := &deviceInfo{ HardwareVendor: "Apple", - HardwareName: "Macbook", + HardwareName: "Macbook Pro", DeviceType: "device", PlatformVendor: "Apple", PlatformName: "MacOs", @@ -650,6 +654,8 @@ func TestHydrateFields(t *testing.T) { HardwareFamily: "Macbook", HardwareModel: "Macbook", HardwareModelVariants: "Macbook", + HardwareNamePrefix: "Macbook", + HardwareNameVersion: "Pro", UserAgent: "ua", DeviceId: "dev-ide", } @@ -700,7 +706,7 @@ func TestHydrateFields(t *testing.T) { require.JSONEq( t, - `{"devicetype":2,"dnt":0,"ext":{"fiftyonedegrees_deviceId":"dev-ide","h":"901","w":843},"geoFetch":1,"h":901,"js":1,"language":"en","make":"Apple","model":"Macintosh","os":"MacOs","osv":"14","pxratio":223,"sua":{"browsers":[{"brand":"Not/A)Brand","version":["99","0","0","0"]},{"brand":"Samsung Internet","version":["23","0","1","1"]},{"brand":"Chromium","version":["115","0","5790","168"]}],"mobile":1,"model":"SM-A037U","platform":{"brand":"Android","version":["13","0","0"]},"source":2},"ua":"Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-A037U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36","w":843}`, + `{"devicetype":2,"dnt":0,"ext":{"fiftyonedegrees_deviceId":"dev-ide","h":"901","w":843},"geoFetch":1,"h":901,"hwv":"Pro","js":1,"language":"en","make":"Apple","model":"Macintosh","os":"MacOs","osv":"14","pxratio":223,"sua":{"browsers":[{"brand":"Not/A)Brand","version":["99","0","0","0"]},{"brand":"Samsung Internet","version":["23","0","1","1"]},{"brand":"Chromium","version":["115","0","5790","168"]}],"mobile":1,"model":"SM-A037U","platform":{"brand":"Android","version":["13","0","0"]},"source":2},"ua":"Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-A037U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36","w":843}`, string(deviceHolder.Device), ) } From 6d85229653b2bce3de6b2f72279543dd3743aa6a Mon Sep 17 00:00:00 2001 From: Patrick Loughrey <ploughrey@triplelift.com> Date: Mon, 10 Aug 2026 22:41:54 -0400 Subject: [PATCH 252/272] Triplelift: Add Currency Conversion Support (#4856) --- adapters/triplelift/triplelift.go | 34 ++++++- .../triplelift/triplelift_currency_test.go | 91 +++++++++++++++++++ .../exemplary/optional-params.json | 1 + .../exemplary/simple-banner-eur-floor.json | 83 +++++++++++++++++ .../exemplary/simple-video.json | 1 + .../supplemental/video-format-11.json | 1 + .../supplemental/video-format-12.json | 1 + .../supplemental/video-format-17.json | 1 + .../triplelift_native/triplelift_native.go | 36 +++++++- .../triplelift_native_currency_test.go | 76 ++++++++++++++++ .../exemplary/app-msn-no-tag-code.json | 1 + .../exemplary/app-msn.json | 1 + .../triplelift_nativetest/exemplary/app.json | 1 + .../exemplary/site-msn-no-tag-code.json | 1 + .../exemplary/site-msn.json | 1 + .../triplelift_nativetest/exemplary/site.json | 1 + .../supplemental/app-publisher-no-domain.json | 1 + .../effective-publisher-allowed.json | 1 + .../site-publisher-no-domain.json | 1 + 19 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 adapters/triplelift/triplelift_currency_test.go create mode 100644 adapters/triplelift/triplelifttest/exemplary/simple-banner-eur-floor.json create mode 100644 adapters/triplelift_native/triplelift_native_currency_test.go diff --git a/adapters/triplelift/triplelift.go b/adapters/triplelift/triplelift.go index 736773075e..fc5f4c641e 100644 --- a/adapters/triplelift/triplelift.go +++ b/adapters/triplelift/triplelift.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v4/adapters" @@ -33,7 +34,7 @@ func getBidType(ext TripleliftRespExt) openrtb_ext.BidType { return openrtb_ext.BidTypeBanner } -func processImp(imp *openrtb2.Imp) error { +func processImp(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { // get the triplelift extension var ext adapters.ExtImpBidder var tlext openrtb_ext.ExtImpTriplelift @@ -48,15 +49,35 @@ func processImp(imp *openrtb2.Imp) error { } imp.TagID = tlext.InvCode // floor is optional - if tlext.Floor == nil { - return nil - } else { + if tlext.Floor != nil { imp.BidFloor = *tlext.Floor } + // Normalize bid floor to USD - TLX expects USD + if err := resolveBidFloorCurrency(imp, reqInfo); err != nil { + return err + } // no error return nil } +// Normalize imp.BidFloor to USD +func resolveBidFloorCurrency(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { + if imp.BidFloor <= 0 { + return nil + } + if imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" { + converted, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") + if err != nil { + return &errortypes.BadInput{ + Message: fmt.Sprintf("Unable to convert bid floor from %s to USD: %s", imp.BidFloorCur, err.Error()), + } + } + imp.BidFloor = converted + } + imp.BidFloorCur = "USD" + return nil +} + func (a *TripleliftAdapter) MakeRequests(request *openrtb2.BidRequest, extra *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { errs := make([]error, 0, len(request.Imp)+1) reqs := make([]*adapters.RequestData, 0, 1) @@ -66,7 +87,7 @@ func (a *TripleliftAdapter) MakeRequests(request *openrtb2.BidRequest, extra *ad var validImps []openrtb2.Imp // pre-process the imps for _, imp := range tlRequest.Imp { - if err := processImp(&imp); err == nil { + if err := processImp(&imp, extra); err == nil { validImps = append(validImps, imp) } else { errs = append(errs, err) @@ -126,6 +147,9 @@ func (a *TripleliftAdapter) MakeBids(internalRequest *openrtb2.BidRequest, exter count := getBidCount(bidResp) bidResponse := adapters.NewBidderResponseWithBidsCapacity(count) + // Bids are always denominated in USD + bidResponse.Currency = "USD" + for _, sb := range bidResp.SeatBid { for i := 0; i < len(sb.Bid); i++ { bid := sb.Bid[i] diff --git a/adapters/triplelift/triplelift_currency_test.go b/adapters/triplelift/triplelift_currency_test.go new file mode 100644 index 0000000000..76611bd35b --- /dev/null +++ b/adapters/triplelift/triplelift_currency_test.go @@ -0,0 +1,91 @@ +package triplelift + +import ( + "errors" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type mockCurrencyConversion struct { + mock.Mock +} + +func (m *mockCurrencyConversion) GetRate(from, to string) (float64, error) { + args := m.Called(from, to) + return args.Get(0).(float64), args.Error(1) +} + +func (m *mockCurrencyConversion) GetRates() *map[string]map[string]float64 { + args := m.Called() + return args.Get(0).(*map[string]map[string]float64) +} + +var currencyTestCases = map[string]struct { + imp openrtb2.Imp + setMock func(m *mock.Mock) + expectedImp openrtb2.Imp + assertError assert.ErrorAssertionFunc +}{ + "no floor, no currency": { + imp: openrtb2.Imp{BidFloor: 0, BidFloorCur: ""}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 0, BidFloorCur: ""}, + assertError: assert.NoError, + }, + "floor, empty currency (implicit USD)": { + imp: openrtb2.Imp{BidFloor: 1.25, BidFloorCur: ""}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 1.25, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "USD floor, no conversion needed": { + imp: openrtb2.Imp{BidFloor: 2.0, BidFloorCur: "USD"}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 2.0, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "usd lowercase - no conversion needed": { + imp: openrtb2.Imp{BidFloor: 2.0, BidFloorCur: "usd"}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 2.0, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "EUR floor converts to USD": { + imp: openrtb2.Imp{BidFloor: 1.0, BidFloorCur: "EUR"}, + setMock: func(m *mock.Mock) { + m.On("GetRate", "EUR", "USD").Return(1.1, nil) + }, + expectedImp: openrtb2.Imp{BidFloor: 1.1, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "unknown currency returns error": { + imp: openrtb2.Imp{BidFloor: 1.0, BidFloorCur: "ABC"}, + setMock: func(m *mock.Mock) { + m.On("GetRate", "ABC", "USD").Return(0.0, errors.New("conversion rate not found")) + }, + expectedImp: openrtb2.Imp{BidFloor: 1.0, BidFloorCur: "ABC"}, + assertError: assert.Error, + }, +} + +func TestResolveBidFloorCurrency(t *testing.T) { + for name, tc := range currencyTestCases { + t.Run(name, func(t *testing.T) { + imp := tc.imp + mockConversions := &mockCurrencyConversion{} + tc.setMock(&mockConversions.Mock) + + reqInfo := adapters.ExtraRequestInfo{CurrencyConversions: mockConversions} + err := resolveBidFloorCurrency(&imp, &reqInfo) + + tc.assertError(t, err) + assert.Equal(t, tc.expectedImp.BidFloor, imp.BidFloor) + assert.Equal(t, tc.expectedImp.BidFloorCur, imp.BidFloorCur) + mockConversions.AssertExpectations(t) + }) + } +} diff --git a/adapters/triplelift/triplelifttest/exemplary/optional-params.json b/adapters/triplelift/triplelifttest/exemplary/optional-params.json index 33da6cb296..52e253ee37 100644 --- a/adapters/triplelift/triplelifttest/exemplary/optional-params.json +++ b/adapters/triplelift/triplelifttest/exemplary/optional-params.json @@ -48,6 +48,7 @@ }, "tagid": "foo", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "foo", diff --git a/adapters/triplelift/triplelifttest/exemplary/simple-banner-eur-floor.json b/adapters/triplelift/triplelifttest/exemplary/simple-banner-eur-floor.json new file mode 100644 index 0000000000..0415711292 --- /dev/null +++ b/adapters/triplelift/triplelifttest/exemplary/simple-banner-eur-floor.json @@ -0,0 +1,83 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "cur": ["USD"], + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300, "h": 250 }] + }, + "bidfloor": 1.0, + "bidfloorcur": "EUR", + "ext": { + "bidder": { "inventoryCode": "aa" } + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { "EUR": { "USD": 1.1 } }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://tlx.3lift.net/s2s/auction?sra=1&supplier_id=20", + "body": { + "id": "test-request-id", + "cur": ["USD"], + "imp": [ + { + "id": "test-imp-id", + "banner": { "format": [{ "w": 300, "h": 250 }] }, + "bidfloor": 1.1, + "bidfloorcur": "USD", + "tagid": "aa", + "ext": { "bidder": { "inventoryCode": "aa" } } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { "EUR": { "USD": 1.1 } }, + "usepbsrates": false + } + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "seat": "958", + "bid": [{ + "id": "b1", "impid": "test-imp-id", "price": 1.5, + "adm": "some-ad", "crid": "cr1", "w": 300, "h": 250, + "ext": { "triplelift_pb": { "format": 2 } } + }] + }], + "bidid": "auction-id" + } + } + } + ], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "b1", "impid": "test-imp-id", "price": 1.5, + "adm": "some-ad", "crid": "cr1", "w": 300, "h": 250, + "ext": { "triplelift_pb": { "format": 2 } } + }, + "type": "banner" + }] + }] +} diff --git a/adapters/triplelift/triplelifttest/exemplary/simple-video.json b/adapters/triplelift/triplelifttest/exemplary/simple-video.json index 8d63b9acf3..66f9eac6c5 100644 --- a/adapters/triplelift/triplelifttest/exemplary/simple-video.json +++ b/adapters/triplelift/triplelifttest/exemplary/simple-video.json @@ -40,6 +40,7 @@ { "tagid": "aaw", "bidfloor": 0.10, + "bidfloorcur": "USD", "id": "test-imp-id", "video": { "mimes": [ diff --git a/adapters/triplelift/triplelifttest/supplemental/video-format-11.json b/adapters/triplelift/triplelifttest/supplemental/video-format-11.json index 372cc51ea0..a1c631bf35 100644 --- a/adapters/triplelift/triplelifttest/supplemental/video-format-11.json +++ b/adapters/triplelift/triplelifttest/supplemental/video-format-11.json @@ -31,6 +31,7 @@ { "tagid": "aaw", "bidfloor": 0.10, + "bidfloorcur": "USD", "id": "test-imp-id", "video": { "mimes": [ "video/mp4"], diff --git a/adapters/triplelift/triplelifttest/supplemental/video-format-12.json b/adapters/triplelift/triplelifttest/supplemental/video-format-12.json index f2b55a0401..026dabbb14 100644 --- a/adapters/triplelift/triplelifttest/supplemental/video-format-12.json +++ b/adapters/triplelift/triplelifttest/supplemental/video-format-12.json @@ -31,6 +31,7 @@ { "tagid": "aaw", "bidfloor": 0.10, + "bidfloorcur": "USD", "id": "test-imp-id", "video": { "mimes": [ "video/mp4"], diff --git a/adapters/triplelift/triplelifttest/supplemental/video-format-17.json b/adapters/triplelift/triplelifttest/supplemental/video-format-17.json index 26dcc943af..f4a591cf40 100644 --- a/adapters/triplelift/triplelifttest/supplemental/video-format-17.json +++ b/adapters/triplelift/triplelifttest/supplemental/video-format-17.json @@ -31,6 +31,7 @@ { "tagid": "aaw", "bidfloor": 0.10, + "bidfloorcur": "USD", "id": "test-imp-id", "video": { "mimes": [ "video/mp4"], diff --git a/adapters/triplelift_native/triplelift_native.go b/adapters/triplelift_native/triplelift_native.go index 987e20d94b..1e102f0d2d 100644 --- a/adapters/triplelift_native/triplelift_native.go +++ b/adapters/triplelift_native/triplelift_native.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v4/adapters" @@ -47,7 +48,7 @@ func getBidType(ext TripleliftRespExt) openrtb_ext.BidType { return openrtb_ext.BidTypeNative } -func processImp(imp *openrtb2.Imp, request *openrtb2.BidRequest) error { +func processImp(imp *openrtb2.Imp, request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) error { // get the triplelift extension var ext ExtImp var tlext openrtb_ext.ExtImpTriplelift @@ -69,14 +70,36 @@ func processImp(imp *openrtb2.Imp, request *openrtb2.BidRequest) error { } // floor is optional - if tlext.Floor == nil { - return nil + if tlext.Floor != nil { + imp.BidFloor = *tlext.Floor + } + + // Normalize bid floor to USD + if err := resolveBidFloorCurrency(imp, reqInfo); err != nil { + return err } - imp.BidFloor = *tlext.Floor return nil } +// Normalize imp.BidFloor to USD +func resolveBidFloorCurrency(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { + if imp.BidFloor <= 0 { + return nil + } + if imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" { + converted, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") + if err != nil { + return &errortypes.BadInput{ + Message: fmt.Sprintf("Unable to convert bid floor from %s to USD: %s", imp.BidFloorCur, err.Error()), + } + } + imp.BidFloor = converted + } + imp.BidFloorCur = "USD" + return nil +} + // msnInApp returns whether msn.com is in request.app.publisher.domain func msnInApp(request *openrtb2.BidRequest) bool { return request.App != nil && request.App.Publisher != nil && request.App.Publisher.Domain == "msn.com" @@ -113,7 +136,7 @@ func (a *TripleliftNativeAdapter) MakeRequests(request *openrtb2.BidRequest, ext var validImps []openrtb2.Imp // pre-process the imps for _, imp := range tlRequest.Imp { - if err := processImp(&imp, request); err == nil { + if err := processImp(&imp, request, extra); err == nil { validImps = append(validImps, imp) } else { errs = append(errs, err) @@ -186,6 +209,9 @@ func (a *TripleliftNativeAdapter) MakeBids(internalRequest *openrtb2.BidRequest, count := getBidCount(bidResp) bidResponse := adapters.NewBidderResponseWithBidsCapacity(count) + // Bids are always denominated in USD + bidResponse.Currency = "USD" + for _, sb := range bidResp.SeatBid { for i := 0; i < len(sb.Bid); i++ { bid := sb.Bid[i] diff --git a/adapters/triplelift_native/triplelift_native_currency_test.go b/adapters/triplelift_native/triplelift_native_currency_test.go new file mode 100644 index 0000000000..8a194bc9b1 --- /dev/null +++ b/adapters/triplelift_native/triplelift_native_currency_test.go @@ -0,0 +1,76 @@ +package triplelift_native + +import ( + "errors" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type mockCurrencyConversion struct { + mock.Mock +} + +func (m *mockCurrencyConversion) GetRate(from, to string) (float64, error) { + args := m.Called(from, to) + return args.Get(0).(float64), args.Error(1) +} + +func (m *mockCurrencyConversion) GetRates() *map[string]map[string]float64 { + args := m.Called() + return args.Get(0).(*map[string]map[string]float64) +} + +func TestResolveBidFloorCurrency(t *testing.T) { + cases := map[string]struct { + imp openrtb2.Imp + setMock func(m *mock.Mock) + expectedImp openrtb2.Imp + assertError assert.ErrorAssertionFunc + }{ + "no floor": { + imp: openrtb2.Imp{BidFloor: 0, BidFloorCur: "EUR"}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 0, BidFloorCur: "EUR"}, + assertError: assert.NoError, + }, + "USD floor passthrough": { + imp: openrtb2.Imp{BidFloor: 3.0, BidFloorCur: "USD"}, + setMock: func(m *mock.Mock) {}, + expectedImp: openrtb2.Imp{BidFloor: 3.0, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "EUR converts to USD": { + imp: openrtb2.Imp{BidFloor: 2.0, BidFloorCur: "EUR"}, + setMock: func(m *mock.Mock) { + m.On("GetRate", "EUR", "USD").Return(1.08, nil) + }, + expectedImp: openrtb2.Imp{BidFloor: 2.16, BidFloorCur: "USD"}, + assertError: assert.NoError, + }, + "conversion error": { + imp: openrtb2.Imp{BidFloor: 1.0, BidFloorCur: "XYZ"}, + setMock: func(m *mock.Mock) { + m.On("GetRate", "XYZ", "USD").Return(0.0, errors.New("rate not found")) + }, + expectedImp: openrtb2.Imp{BidFloor: 1.0, BidFloorCur: "XYZ"}, + assertError: assert.Error, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + imp := tc.imp + m := &mockCurrencyConversion{} + tc.setMock(&m.Mock) + reqInfo := adapters.ExtraRequestInfo{CurrencyConversions: m} + err := resolveBidFloorCurrency(&imp, &reqInfo) + tc.assertError(t, err) + assert.Equal(t, tc.expectedImp.BidFloor, imp.BidFloor) + assert.Equal(t, tc.expectedImp.BidFloorCur, imp.BidFloorCur) + m.AssertExpectations(t) + }) + } +} diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn-no-tag-code.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn-no-tag-code.json index 6950942f19..e6a91ded53 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn-no-tag-code.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn-no-tag-code.json @@ -36,6 +36,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn.json index 420cab5aff..570456c8bb 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/app-msn.json @@ -36,6 +36,7 @@ }, "tagid": "bar", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/app.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/app.json index d1cd72947b..c6a36ee0af 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/app.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/app.json @@ -36,6 +36,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn-no-tag-code.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn-no-tag-code.json index 48162742a1..8ad19e9eef 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn-no-tag-code.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn-no-tag-code.json @@ -36,6 +36,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn.json index 5aaa5a1ddc..dbb1091f4f 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/site-msn.json @@ -36,6 +36,7 @@ }, "tagid": "bar", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/exemplary/site.json b/adapters/triplelift_native/triplelift_nativetest/exemplary/site.json index d273f4d411..a281ab34e4 100644 --- a/adapters/triplelift_native/triplelift_nativetest/exemplary/site.json +++ b/adapters/triplelift_native/triplelift_nativetest/exemplary/site.json @@ -36,6 +36,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/supplemental/app-publisher-no-domain.json b/adapters/triplelift_native/triplelift_nativetest/supplemental/app-publisher-no-domain.json index ac119354c3..65e5cfe6df 100644 --- a/adapters/triplelift_native/triplelift_nativetest/supplemental/app-publisher-no-domain.json +++ b/adapters/triplelift_native/triplelift_nativetest/supplemental/app-publisher-no-domain.json @@ -34,6 +34,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/supplemental/effective-publisher-allowed.json b/adapters/triplelift_native/triplelift_nativetest/supplemental/effective-publisher-allowed.json index 74ac929478..c5d3337d1a 100644 --- a/adapters/triplelift_native/triplelift_nativetest/supplemental/effective-publisher-allowed.json +++ b/adapters/triplelift_native/triplelift_nativetest/supplemental/effective-publisher-allowed.json @@ -41,6 +41,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", diff --git a/adapters/triplelift_native/triplelift_nativetest/supplemental/site-publisher-no-domain.json b/adapters/triplelift_native/triplelift_nativetest/supplemental/site-publisher-no-domain.json index d44ae442fa..2e3a4d0fa5 100644 --- a/adapters/triplelift_native/triplelift_nativetest/supplemental/site-publisher-no-domain.json +++ b/adapters/triplelift_native/triplelift_nativetest/supplemental/site-publisher-no-domain.json @@ -35,6 +35,7 @@ }, "tagid": "invcode", "bidfloor": 20, + "bidfloorcur": "USD", "ext": { "bidder": { "inventoryCode": "invcode", From ec99cc6ddada68f5af128d0eef338ab8eef36b3f Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Tue, 11 Aug 2026 06:01:51 +0300 Subject: [PATCH 253/272] New Adapter: SMB (#4834) --- static/bidder-info/smb.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 static/bidder-info/smb.yaml diff --git a/static/bidder-info/smb.yaml b/static/bidder-info/smb.yaml new file mode 100644 index 0000000000..64d47d793d --- /dev/null +++ b/static/bidder-info/smb.yaml @@ -0,0 +1,16 @@ +aliasOf: "teqblaze" +endpoint: "http://be.smartbid.ai/pserver" +maintainer: + email: "support@smartbid.ai" +capabilities: + site: + mediaTypes: + - banner + - video + - native + + app: + mediaTypes: + - banner + - video + - native \ No newline at end of file From 85e52d8e2dab3b1b9a82d9be9e2de94d57cb57a6 Mon Sep 17 00:00:00 2001 From: austinbyron <59710247+austinbyron@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:15:18 -0700 Subject: [PATCH 254/272] New Adapter: Ezoic (#4823) --- adapters/ezoic/ezoic.go | 95 ++++++++++++ adapters/ezoic/ezoic_test.go | 57 ++++++++ .../ezoictest/exemplary/simple-banner.json | 124 ++++++++++++++++ .../ezoictest/exemplary/simple-native.json | 112 ++++++++++++++ .../ezoictest/exemplary/simple-video.json | 138 ++++++++++++++++++ .../supplemental/invalid-response.json | 69 +++++++++ .../ezoictest/supplemental/status-204.json | 63 ++++++++ .../ezoictest/supplemental/status-400.json | 69 +++++++++ .../ezoictest/supplemental/status-500.json | 69 +++++++++ .../supplemental/unsupported-mtype.json | 117 +++++++++++++++ adapters/ezoic/params_test.go | 52 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_ezoic.go | 8 + static/bidder-info/ezoic.yaml | 23 +++ static/bidder-params/ezoic.json | 13 ++ 16 files changed, 1013 insertions(+) create mode 100644 adapters/ezoic/ezoic.go create mode 100644 adapters/ezoic/ezoic_test.go create mode 100644 adapters/ezoic/ezoictest/exemplary/simple-banner.json create mode 100644 adapters/ezoic/ezoictest/exemplary/simple-native.json create mode 100644 adapters/ezoic/ezoictest/exemplary/simple-video.json create mode 100644 adapters/ezoic/ezoictest/supplemental/invalid-response.json create mode 100644 adapters/ezoic/ezoictest/supplemental/status-204.json create mode 100644 adapters/ezoic/ezoictest/supplemental/status-400.json create mode 100644 adapters/ezoic/ezoictest/supplemental/status-500.json create mode 100644 adapters/ezoic/ezoictest/supplemental/unsupported-mtype.json create mode 100644 adapters/ezoic/params_test.go create mode 100644 openrtb_ext/imp_ezoic.go create mode 100644 static/bidder-info/ezoic.yaml create mode 100644 static/bidder-params/ezoic.json diff --git a/adapters/ezoic/ezoic.go b/adapters/ezoic/ezoic.go new file mode 100644 index 0000000000..fd5e51950d --- /dev/null +++ b/adapters/ezoic/ezoic.go @@ -0,0 +1,95 @@ +package ezoic + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the Ezoic adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, cfg config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{endpoint: cfg.Endpoint}, nil +} + +// MakeRequests forwards the OpenRTB request to the Ezoic bidder endpoint +// unchanged. Eligibility, demand selection, and creative construction all +// happen server-side at Ezoic; the adapter is a deliberately thin transport. +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + body, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{fmt.Errorf("unable to marshal openrtb request: %w", err)} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + return []*adapters.RequestData{{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: body, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }}, nil +} + +// MakeBids unpacks the Ezoic endpoint's OpenRTB BidResponse. +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if bidResp.Cur != "" { + bidderResponse.Currency = bidResp.Cur + } + + var errs []error + for _, seatBid := range bidResp.SeatBid { + for i := range seatBid.Bid { + bidType, err := getMediaTypeForBid(seatBid.Bid[i]) + if err != nil { + errs = append(errs, err) + continue + } + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + return bidderResponse, errs +} + +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 + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported mtype %d for bid %s", bid.MType, bid.ID), + } + } +} diff --git a/adapters/ezoic/ezoic_test.go b/adapters/ezoic/ezoic_test.go new file mode 100644 index 0000000000..0c9a24a953 --- /dev/null +++ b/adapters/ezoic/ezoic_test.go @@ -0,0 +1,57 @@ +package ezoic + +import ( + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +const testsBidderEndpoint = "https://g.ezoic.net/ezoic/prebid/adapter/ortb" + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderEzoic, config.Adapter{ + Endpoint: testsBidderEndpoint}, config.Server{}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "ezoictest", bidder) +} + +func TestNoContentResponse(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderEzoic, config.Adapter{ + Endpoint: testsBidderEndpoint}, config.Server{}) + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidResponse, errs := bidder.MakeBids(nil, nil, &adapters.ResponseData{StatusCode: 204}) + assert.Nil(t, bidResponse) + assert.Empty(t, errs) +} + +func TestGetMediaTypeForBid(t *testing.T) { + bidType, err := getMediaTypeForBid(openrtb2.Bid{MType: openrtb2.MarkupBanner}) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeBanner, bidType) + + bidType, err = getMediaTypeForBid(openrtb2.Bid{MType: openrtb2.MarkupVideo}) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeVideo, bidType) + + bidType, err = getMediaTypeForBid(openrtb2.Bid{MType: openrtb2.MarkupNative}) + assert.NoError(t, err) + assert.Equal(t, openrtb_ext.BidTypeNative, bidType) + + _, err = getMediaTypeForBid(openrtb2.Bid{ID: "no-mtype"}) + assert.Error(t, err) + + _, err = getMediaTypeForBid(openrtb2.Bid{ID: "audio", MType: openrtb2.MarkupAudio}) + assert.Error(t, err) +} diff --git a/adapters/ezoic/ezoictest/exemplary/simple-banner.json b/adapters/ezoic/ezoictest/exemplary/simple-banner.json new file mode 100644 index 0000000000..7c3c29b291 --- /dev/null +++ b/adapters/ezoic/ezoictest/exemplary/simple-banner.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "ezoic", + "bid": [ + { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<div>ezoic-self-tracking-creative</div>", + "crid": "ezoic-creative-1", + "w": 300, + "h": 250, + "mtype": 1, + "exp": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<div>ezoic-self-tracking-creative</div>", + "crid": "ezoic-creative-1", + "w": 300, + "h": 250, + "mtype": 1, + "exp": 300 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/ezoic/ezoictest/exemplary/simple-native.json b/adapters/ezoic/ezoictest/exemplary/simple-native.json new file mode 100644 index 0000000000..31a072cd61 --- /dev/null +++ b/adapters/ezoic/ezoictest/exemplary/simple-native.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}}]}" + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "native": { + "ver": "1.2", + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}}]}" + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "ezoic", + "bid": [ + { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 1.75, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"ezoic native title\"}}],\"link\":{\"url\":\"https://example.com/click\"}}}", + "crid": "ezoic-creative-1", + "mtype": 4, + "exp": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 1.75, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"ezoic native title\"}}],\"link\":{\"url\":\"https://example.com/click\"}}}", + "crid": "ezoic-creative-1", + "mtype": 4, + "exp": 300 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/ezoic/ezoictest/exemplary/simple-video.json b/adapters/ezoic/ezoictest/exemplary/simple-video.json new file mode 100644 index 0000000000..6db45edc5e --- /dev/null +++ b/adapters/ezoic/ezoictest/exemplary/simple-video.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 640, + "h": 480, + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "tmax": 750, + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "device": { + "ua": "test-user-agent", + "ip": "203.0.113.9" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "div-gpt-ad-1", + "bidfloor": 0.25, + "bidfloorcur": "USD", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 640, + "h": 480, + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "placementId": "ezoic-placement-1" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "ezoic", + "bid": [ + { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine></InLine></Ad></VAST>", + "crid": "ezoic-creative-1", + "w": 640, + "h": 480, + "mtype": 2, + "exp": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "ezoic-bid-1", + "impid": "test-imp-id", + "price": 4.5, + "adm": "<VAST version=\"4.0\"><Ad><InLine></InLine></Ad></VAST>", + "crid": "ezoic-creative-1", + "w": 640, + "h": 480, + "mtype": 2, + "exp": 300 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/ezoic/ezoictest/supplemental/invalid-response.json b/adapters/ezoic/ezoictest/supplemental/invalid-response.json new file mode 100644 index 0000000000..adcb3c1001 --- /dev/null +++ b/adapters/ezoic/ezoictest/supplemental/invalid-response.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "expect", + "comparison": "regex" + } + ] +} diff --git a/adapters/ezoic/ezoictest/supplemental/status-204.json b/adapters/ezoic/ezoictest/supplemental/status-204.json new file mode 100644 index 0000000000..2c60ef485a --- /dev/null +++ b/adapters/ezoic/ezoictest/supplemental/status-204.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/ezoic/ezoictest/supplemental/status-400.json b/adapters/ezoic/ezoictest/supplemental/status-400.json new file mode 100644 index 0000000000..8d156eb86a --- /dev/null +++ b/adapters/ezoic/ezoictest/supplemental/status-400.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/ezoic/ezoictest/supplemental/status-500.json b/adapters/ezoic/ezoictest/supplemental/status-500.json new file mode 100644 index 0000000000..1d0b418290 --- /dev/null +++ b/adapters/ezoic/ezoictest/supplemental/status-500.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/ezoic/ezoictest/supplemental/unsupported-mtype.json b/adapters/ezoic/ezoictest/supplemental/unsupported-mtype.json new file mode 100644 index 0000000000..39d7506d66 --- /dev/null +++ b/adapters/ezoic/ezoictest/supplemental/unsupported-mtype.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://g.ezoic.net/ezoic/prebid/adapter/ortb", + "body": { + "id": "test-request-id", + "site": { + "page": "https://example.com/article", + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "ezoic", + "bid": [ + { + "id": "ezoic-bid-good", + "impid": "test-imp-id", + "price": 1.25, + "adm": "<div>creative</div>", + "crid": "ezoic-creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + { + "id": "ezoic-bid-no-mtype", + "impid": "test-imp-id", + "price": 9.99, + "adm": "<div>creative</div>", + "crid": "ezoic-creative-2", + "w": 300, + "h": 250 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "ezoic-bid-good", + "impid": "test-imp-id", + "price": 1.25, + "adm": "<div>creative</div>", + "crid": "ezoic-creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported mtype 0 for bid ezoic-bid-no-mtype", + "comparison": "literal" + } + ] +} diff --git a/adapters/ezoic/params_test.go b/adapters/ezoic/params_test.go new file mode 100644 index 0000000000..91994fe4cf --- /dev/null +++ b/adapters/ezoic/params_test.go @@ -0,0 +1,52 @@ +package ezoic + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +// This file intends to test static/bidder-params/ezoic.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.ezoic + +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.BidderEzoic, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected ezoic 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.BidderEzoic, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{}`, + `{"placementId": "ezoic-placement-1"}`, +} + +var invalidParams = []string{ + `null`, + `true`, + `[]`, + `"placementId"`, + `{"placementId": 12345}`, + `{"placementId": true}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 9f02d8bdef..8962fc3c9f 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -106,6 +106,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/escalax" "github.com/prebid/prebid-server/v4/adapters/eskimi" "github.com/prebid/prebid-server/v4/adapters/exco" + "github.com/prebid/prebid-server/v4/adapters/ezoic" "github.com/prebid/prebid-server/v4/adapters/feedad" "github.com/prebid/prebid-server/v4/adapters/flatads" "github.com/prebid/prebid-server/v4/adapters/flipp" @@ -381,6 +382,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEskimi: eskimi.Builder, openrtb_ext.BidderExco: exco.Builder, openrtb_ext.BidderEVolution: evolution.Builder, + openrtb_ext.BidderEzoic: ezoic.Builder, openrtb_ext.BidderFeedAd: feedad.Builder, openrtb_ext.BidderFlatads: flatads.Builder, openrtb_ext.BidderFlipp: flipp.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 5b2dd8418f..6f1d0f52db 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -123,6 +123,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderEskimi, BidderEVolution, BidderExco, + BidderEzoic, BidderFeedAd, BidderFlatads, BidderFlipp, @@ -504,6 +505,7 @@ const ( BidderEskimi BidderName = "eskimi" BidderExco BidderName = "exco" BidderEVolution BidderName = "e_volution" + BidderEzoic BidderName = "ezoic" BidderFeedAd BidderName = "feedad" BidderFlatads BidderName = "flatads" BidderFlipp BidderName = "flipp" diff --git a/openrtb_ext/imp_ezoic.go b/openrtb_ext/imp_ezoic.go new file mode 100644 index 0000000000..609650ad5e --- /dev/null +++ b/openrtb_ext/imp_ezoic.go @@ -0,0 +1,8 @@ +package openrtb_ext + +// ExtImpEzoic defines the contract for bidrequest.imp[i].ext.prebid.bidder.ezoic. +// Ezoic eligibility is resolved server-side from site.domain, so no params are +// required; placementId is an optional onboarding-assigned identifier. +type ExtImpEzoic struct { + PlacementID string `json:"placementId,omitempty"` +} diff --git a/static/bidder-info/ezoic.yaml b/static/bidder-info/ezoic.yaml new file mode 100644 index 0000000000..9f8be82b52 --- /dev/null +++ b/static/bidder-info/ezoic.yaml @@ -0,0 +1,23 @@ +# Ezoic requires publisher domains to be registered and approved before +# bidding; unapproved inventory receives no-bid responses. Contact +# prebid@ezoic.com to get set up. +endpoint: "https://g.ezoic.net/ezoic/prebid/adapter/ortb" +maintainer: + email: prebid@ezoic.com +gvlVendorID: 347 +geoscope: + - global +openrtb: + version: 2.6 +modifyingVastXmlAllowed: false +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/ezoic.json b/static/bidder-params/ezoic.json new file mode 100644 index 0000000000..ecd916a461 --- /dev/null +++ b/static/bidder-params/ezoic.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Ezoic Adapter Params", + "description": "A schema which validates params accepted by the Ezoic adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "Optional placement identifier assigned during Ezoic onboarding" + } + }, + "required": [] +} From df0c2bf0f4e35df7a4b9602b19c3151fc4804f30 Mon Sep 17 00:00:00 2001 From: Luke Novak <contact@nluken.com> Date: Mon, 10 Aug 2026 23:37:39 -0400 Subject: [PATCH 255/272] Kargo: Add app capabilites in YAML --- static/bidder-info/kargo.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/bidder-info/kargo.yaml b/static/bidder-info/kargo.yaml index accbf1a3fc..1347a87eb4 100644 --- a/static/bidder-info/kargo.yaml +++ b/static/bidder-info/kargo.yaml @@ -9,6 +9,11 @@ capabilities: - banner - video - native + app: + mediaTypes: + - banner + - video + - native userSync: redirect: url: "https://crb.kargo.com/api/v1/dsync/PrebidServer?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" From b1d17e13421840337eed3bd59fcec064566a0281 Mon Sep 17 00:00:00 2001 From: akshatgmnet <akshat.g@media.net> Date: Tue, 18 Aug 2026 08:05:22 +0530 Subject: [PATCH 256/272] Medianet: Update cookie sync url (#4743) --- static/bidder-info/medianet.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/medianet.yaml b/static/bidder-info/medianet.yaml index effd768206..73c1830e3e 100644 --- a/static/bidder-info/medianet.yaml +++ b/static/bidder-info/medianet.yaml @@ -23,5 +23,5 @@ userSync: url: https://hbx.media.net/checksync.php?cid=8CUEHS6F9&cs=87&type=mpbc&cv=37&vsSync=1&uspstring={{.USPrivacy}}&gdpr={{.GDPR}}&gdprstring={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}} userMacro: "<vsid>" redirect: - url: https://hbx.media.net/cksync.php?cs=1&type=pbs&ovsid=setstatuscode&bidder=medianet&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} - userMacro: "<vsid>" \ No newline at end of file + url: https://cs.media.net/cksync.php?cs=1&type=pbs&ovsid=setstatuscode&bidder=medianet&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: "<vsid>" From ec855e70ffbf6c2f84149e7a36ed40368c7107ca Mon Sep 17 00:00:00 2001 From: Anthony <anthonyrichir@users.noreply.github.com> Date: Tue, 18 Aug 2026 16:11:43 +0200 Subject: [PATCH 257/272] New Adapter: Proxistore (#4731) --- .../workflows/scripts/codepath-notification | 1 + adapters/proxistore/params_test.go | 47 ++++++ adapters/proxistore/proxistore.go | 97 +++++++++++ adapters/proxistore/proxistore_test.go | 27 ++++ .../exemplary/multi-imp-banner.json | 151 ++++++++++++++++++ .../exemplary/simple-audio.json | 108 +++++++++++++ .../exemplary/simple-banner-app.json | 138 ++++++++++++++++ .../exemplary/simple-banner.json | 130 +++++++++++++++ .../exemplary/simple-native.json | 104 ++++++++++++ .../exemplary/simple-video.json | 118 ++++++++++++++ .../supplemental/bad-response.json | 61 +++++++ .../supplemental/status-204.json | 55 +++++++ .../supplemental/status-400.json | 61 +++++++ .../supplemental/status-500.json | 61 +++++++ .../supplemental/unsupported-mtype.json | 86 ++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_proxistore.go | 6 + static/bidder-info/proxistore.yaml | 29 ++++ static/bidder-params/proxistore.json | 19 +++ 20 files changed, 1303 insertions(+) create mode 100644 adapters/proxistore/params_test.go create mode 100644 adapters/proxistore/proxistore.go create mode 100644 adapters/proxistore/proxistore_test.go create mode 100644 adapters/proxistore/proxistoretest/exemplary/multi-imp-banner.json create mode 100644 adapters/proxistore/proxistoretest/exemplary/simple-audio.json create mode 100644 adapters/proxistore/proxistoretest/exemplary/simple-banner-app.json create mode 100644 adapters/proxistore/proxistoretest/exemplary/simple-banner.json create mode 100644 adapters/proxistore/proxistoretest/exemplary/simple-native.json create mode 100644 adapters/proxistore/proxistoretest/exemplary/simple-video.json create mode 100644 adapters/proxistore/proxistoretest/supplemental/bad-response.json create mode 100644 adapters/proxistore/proxistoretest/supplemental/status-204.json create mode 100644 adapters/proxistore/proxistoretest/supplemental/status-400.json create mode 100644 adapters/proxistore/proxistoretest/supplemental/status-500.json create mode 100644 adapters/proxistore/proxistoretest/supplemental/unsupported-mtype.json create mode 100644 openrtb_ext/imp_proxistore.go create mode 100644 static/bidder-info/proxistore.yaml create mode 100644 static/bidder-params/proxistore.json diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification index 8a3bae8dac..b917c6d201 100644 --- a/.github/workflows/scripts/codepath-notification +++ b/.github/workflows/scripts/codepath-notification @@ -19,3 +19,4 @@ adapters/ix|imp_ix|ix.json|ix.yaml: pdu-supply-prebid@indexexchange.com medianet: prebid@media.net gumgum: prebid@gumgum.com kargo: kraken@kargo.com +proxistore: proxistore-technics@proxistore.com diff --git a/adapters/proxistore/params_test.go b/adapters/proxistore/params_test.go new file mode 100644 index 0000000000..0d2f987f50 --- /dev/null +++ b/adapters/proxistore/params_test.go @@ -0,0 +1,47 @@ +package proxistore + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema. %v", err) + + for _, p := range validParams { + err := validator.Validate(openrtb_ext.BidderProxistore, json.RawMessage(p)) + assert.NoError(t, err, "Schema rejected valid params: %s", p) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema. %v", err) + + for _, p := range invalidParams { + err := validator.Validate(openrtb_ext.BidderProxistore, json.RawMessage(p)) + assert.Error(t, err, "Schema allowed invalid params: %s", p) + } +} + +var validParams = []string{ + `{"website": "example.com", "language": "fr"}`, + `{"website": "test-site", "language": "en"}`, + `{"website": "publisher.be", "language": "nl"}`, +} + +var invalidParams = []string{ + `{}`, + `{"website": "example.com"}`, + `{"language": "fr"}`, + `{"website": "", "language": "fr"}`, + `{"website": "example.com", "language": ""}`, + `{"website": 123, "language": "fr"}`, + `{"website": "example.com", "language": 456}`, + `null`, +} diff --git a/adapters/proxistore/proxistore.go b/adapters/proxistore/proxistore.go new file mode 100644 index 0000000000..9952f1bc4c --- /dev/null +++ b/adapters/proxistore/proxistore.go @@ -0,0 +1,97 @@ +package proxistore + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json") + headers.Add("Accept", "application/json") + headers.Add("X-Prebid-Source", "server") + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: requestJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + + var errors []error + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errors = append(errors, err) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + + return bidResponse, errors +} + +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.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported MType %d for bid %s", bid.MType, bid.ID), + } + } +} diff --git a/adapters/proxistore/proxistore_test.go b/adapters/proxistore/proxistore_test.go new file mode 100644 index 0000000000..826607ecae --- /dev/null +++ b/adapters/proxistore/proxistore_test.go @@ -0,0 +1,27 @@ +package proxistore + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderProxistore, + config.Adapter{ + Endpoint: "https://api.proxistore.com/v3/rtb/openrtb", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 1, + DataCenter: "2", + }, + ) + + assert.NoError(t, buildErr) + adapterstest.RunJSONBidderTest(t, "proxistoretest", bidder) +} diff --git a/adapters/proxistore/proxistoretest/exemplary/multi-imp-banner.json b/adapters/proxistore/proxistoretest/exemplary/multi-imp-banner.json new file mode 100644 index 0000000000..cab78da49b --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/multi-imp-banner.json @@ -0,0 +1,151 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0" + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + }, + { + "id": "imp-2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0" + }, + "site": { + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + }, + { + "id": "imp-2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["imp-1", "imp-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "imp-1", + "price": 1.50, + "adm": "<div>Ad 1</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + { + "id": "bid-2", + "impid": "imp-2", + "price": 0.80, + "adm": "<div>Ad 2</div>", + "crid": "creative-2", + "w": 728, + "h": 90, + "mtype": 1 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-1", + "price": 1.50, + "adm": "<div>Ad 1</div>", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-2", + "impid": "imp-2", + "price": 0.80, + "adm": "<div>Ad 2</div>", + "crid": "creative-2", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/exemplary/simple-audio.json b/adapters/proxistore/proxistoretest/exemplary/simple-audio.json new file mode 100644 index 0000000000..4bcea39364 --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/simple-audio.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp3"], + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp3"], + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "<DAAST version=\"1.0\"></DAAST>", + "adomain": ["advertiser.com"], + "crid": "creative-audio-123", + "mtype": 3 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "<DAAST version=\"1.0\"></DAAST>", + "adomain": ["advertiser.com"], + "crid": "creative-audio-123", + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/exemplary/simple-banner-app.json b/adapters/proxistore/proxistoretest/exemplary/simple-banner-app.json new file mode 100644 index 0000000000..bfc01eca1c --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/simple-banner-app.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36" + }, + "app": { + "id": "app-id", + "bundle": "com.example.app", + "name": "Example App", + "domain": "example.com", + "publisher": { + "id": "pub-123" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 320, "h": 50}, + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ], + "regs": { + "gdpr": 1 + }, + "user": { + "ext": { + "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36" + }, + "app": { + "id": "app-id", + "bundle": "com.example.app", + "name": "Example App", + "domain": "example.com", + "publisher": { + "id": "pub-123" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 320, "h": 50}, + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ], + "regs": { + "gdpr": 1 + }, + "user": { + "ext": { + "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.85, + "adm": "<div>App banner creative</div>", + "adomain": ["advertiser.com"], + "crid": "creative-456", + "w": 320, + "h": 50, + "mtype": 1 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.85, + "adm": "<div>App banner creative</div>", + "adomain": ["advertiser.com"], + "crid": "creative-456", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/exemplary/simple-banner.json b/adapters/proxistore/proxistoretest/exemplary/simple-banner.json new file mode 100644 index 0000000000..a3006eed94 --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/simple-banner.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250}, + {"w": 300, "h": 600} + ] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ], + "regs": { + "gdpr": 1 + }, + "user": { + "ext": { + "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250}, + {"w": 300, "h": 600} + ] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ], + "regs": { + "gdpr": 1 + }, + "user": { + "ext": { + "consent": "COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.23, + "adm": "<div>Ad creative</div>", + "adomain": ["advertiser.com"], + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.23, + "adm": "<div>Ad creative</div>", + "adomain": ["advertiser.com"], + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/exemplary/simple-native.json b/adapters/proxistore/proxistoretest/exemplary/simple-native.json new file mode 100644 index 0000000000..b0146495cd --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/simple-native.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}}]}" + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}}]}" + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.80, + "adm": "{\"native\":{\"ver\":\"1.1\",\"link\":{\"url\":\"https://example.com\"},\"assets\":[{\"id\":1,\"title\":{\"text\":\"Ad Title\"}}]}}", + "adomain": ["advertiser.com"], + "crid": "creative-native-123", + "mtype": 4 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.80, + "adm": "{\"native\":{\"ver\":\"1.1\",\"link\":{\"url\":\"https://example.com\"},\"assets\":[{\"id\":1,\"title\":{\"text\":\"Ad Title\"}}]}}", + "adomain": ["advertiser.com"], + "crid": "creative-native-123", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/exemplary/simple-video.json b/adapters/proxistore/proxistoretest/exemplary/simple-video.json new file mode 100644 index 0000000000..192eb60295 --- /dev/null +++ b/adapters/proxistore/proxistoretest/exemplary/simple-video.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [1, 2], + "w": 640, + "h": 480, + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }, + "site": { + "id": "site-id", + "domain": "example.com", + "page": "https://example.com/page" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [1, 2], + "w": 640, + "h": 480, + "minduration": 5, + "maxduration": 30 + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.50, + "adm": "<VAST version=\"3.0\"><Ad></Ad></VAST>", + "adomain": ["advertiser.com"], + "crid": "creative-video-123", + "w": 640, + "h": 480, + "mtype": 2 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.50, + "adm": "<VAST version=\"3.0\"><Ad></Ad></VAST>", + "adomain": ["advertiser.com"], + "crid": "creative-video-123", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/proxistore/proxistoretest/supplemental/bad-response.json b/adapters/proxistore/proxistoretest/supplemental/bad-response.json new file mode 100644 index 0000000000..850d729e25 --- /dev/null +++ b/adapters/proxistore/proxistoretest/supplemental/bad-response.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "not valid json" + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/proxistore/proxistoretest/supplemental/status-204.json b/adapters/proxistore/proxistoretest/supplemental/status-204.json new file mode 100644 index 0000000000..1375e9c65f --- /dev/null +++ b/adapters/proxistore/proxistoretest/supplemental/status-204.json @@ -0,0 +1,55 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/proxistore/proxistoretest/supplemental/status-400.json b/adapters/proxistore/proxistoretest/supplemental/status-400.json new file mode 100644 index 0000000000..ef772ce672 --- /dev/null +++ b/adapters/proxistore/proxistoretest/supplemental/status-400.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/proxistore/proxistoretest/supplemental/status-500.json b/adapters/proxistore/proxistoretest/supplemental/status-500.json new file mode 100644 index 0000000000..b8595ed9db --- /dev/null +++ b/adapters/proxistore/proxistoretest/supplemental/status-500.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/proxistore/proxistoretest/supplemental/unsupported-mtype.json b/adapters/proxistore/proxistoretest/supplemental/unsupported-mtype.json new file mode 100644 index 0000000000..5141e24f1d --- /dev/null +++ b/adapters/proxistore/proxistoretest/supplemental/unsupported-mtype.json @@ -0,0 +1,86 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://api.proxistore.com/v3/rtb/openrtb", + "body": { + "id": "test-request-id", + "site": { + "domain": "example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "website": "example.com", + "language": "fr" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.23, + "adm": "<div>Ad creative</div>", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 99 + } + ], + "seat": "proxistore" + } + ], + "cur": "EUR" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "EUR", + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported MType 99 for bid test-bid-id", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 8962fc3c9f..7b722739fd 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -186,6 +186,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/pangle" "github.com/prebid/prebid-server/v4/adapters/pgamssp" "github.com/prebid/prebid-server/v4/adapters/playdigo" + "github.com/prebid/prebid-server/v4/adapters/proxistore" "github.com/prebid/prebid-server/v4/adapters/pubmatic" "github.com/prebid/prebid-server/v4/adapters/pubnative" "github.com/prebid/prebid-server/v4/adapters/pubrise" @@ -464,6 +465,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderPangle: pangle.Builder, openrtb_ext.BidderPGAMSsp: pgamssp.Builder, openrtb_ext.BidderPlaydigo: playdigo.Builder, + openrtb_ext.BidderProxistore: proxistore.Builder, openrtb_ext.BidderPubmatic: pubmatic.Builder, openrtb_ext.BidderPubnative: pubnative.Builder, openrtb_ext.BidderPubrise: pubrise.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 6f1d0f52db..9677e235fe 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -204,6 +204,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderPangle, BidderPGAMSsp, BidderPlaydigo, + BidderProxistore, BidderPubmatic, BidderPubrise, BidderPubnative, @@ -586,6 +587,7 @@ const ( BidderPangle BidderName = "pangle" BidderPGAMSsp BidderName = "pgamssp" BidderPlaydigo BidderName = "playdigo" + BidderProxistore BidderName = "proxistore" BidderPubmatic BidderName = "pubmatic" BidderPubrise BidderName = "pubrise" BidderPubnative BidderName = "pubnative" diff --git a/openrtb_ext/imp_proxistore.go b/openrtb_ext/imp_proxistore.go new file mode 100644 index 0000000000..6c6b5bd5f0 --- /dev/null +++ b/openrtb_ext/imp_proxistore.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ExtImpProxistore struct { + Website string `json:"website"` + Language string `json:"language"` +} diff --git a/static/bidder-info/proxistore.yaml b/static/bidder-info/proxistore.yaml new file mode 100644 index 0000000000..49fb1828cf --- /dev/null +++ b/static/bidder-info/proxistore.yaml @@ -0,0 +1,29 @@ +endpoint: "https://api.proxistore.com/v3/rtb/openrtb" +endpointCompression: gzip +geoscope: + - EEA +maintainer: + email: support@proxistore.com +gvlVendorID: 418 +openrtb: + version: 2.6 +capabilities: + app: + mediaTypes: + - banner + - video + - native + - audio + site: + mediaTypes: + - banner + - video + - native + - audio +userSync: + redirect: + url: https://abs.proxistore.com/v3/rtb/sync/prebid-server/redirect?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirect={{.RedirectURL}} + userMacro: $UID + iframe: + url: https://abs.proxistore.com/v3/rtb/sync/prebid-server/iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirect={{.RedirectURL}} + userMacro: $UID \ No newline at end of file diff --git a/static/bidder-params/proxistore.json b/static/bidder-params/proxistore.json new file mode 100644 index 0000000000..d9360a49ce --- /dev/null +++ b/static/bidder-params/proxistore.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Proxistore Adapter Params", + "description": "A schema which validates params accepted by the Proxistore adapter", + "type": "object", + "properties": { + "website": { + "type": "string", + "minLength": 1, + "description": "Publisher website identifier" + }, + "language": { + "type": "string", + "minLength": 1, + "description": "Language code (e.g., 'fr', 'en')" + } + }, + "required": ["website", "language"] +} \ No newline at end of file From 3d8624c1f54998bd9b1683d9c7f913aff55cdcad Mon Sep 17 00:00:00 2001 From: franklong-sa <frank.long@stackadapt.com> Date: Tue, 18 Aug 2026 10:21:37 -0400 Subject: [PATCH 258/272] New Adapter: StackAdapt (#4724) --- adapters/stackadapt/params_test.go | 60 +++ adapters/stackadapt/stackadapt.go | 228 +++++++++ adapters/stackadapt/stackadapt_test.go | 454 ++++++++++++++++++ .../stackadapttest/exemplary/app-banner.json | 93 ++++ .../stackadapttest/exemplary/multi-imp.json | 179 +++++++ .../exemplary/simple-web-audio.json | 84 ++++ .../exemplary/simple-web-banner.json | 114 +++++ .../exemplary/simple-web-native.json | 80 +++ .../exemplary/simple-web-video.json | 94 ++++ .../app-with-existing-publisher.json | 95 ++++ .../supplemental/auction-price-macro.json | 92 ++++ .../supplemental/bad-bidder-ext.json | 24 + .../supplemental/endpoint-param-escaping.json | 58 +++ .../supplemental/multi-imp-mismatch.json | 43 ++ .../supplemental/native-adm-invalid.json | 74 +++ .../supplemental/no-content.json | 58 +++ .../site-with-existing-publisher.json | 93 ++++ .../supplemental/status-400.json | 61 +++ .../supplemental/unsupported-mtype.json | 80 +++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_stackadapt.go | 13 + static/bidder-info/stackadapt.yaml | 24 + static/bidder-params/stackadapt.json | 42 ++ 24 files changed, 2147 insertions(+) create mode 100644 adapters/stackadapt/params_test.go create mode 100644 adapters/stackadapt/stackadapt.go create mode 100644 adapters/stackadapt/stackadapt_test.go create mode 100644 adapters/stackadapt/stackadapttest/exemplary/app-banner.json create mode 100644 adapters/stackadapt/stackadapttest/exemplary/multi-imp.json create mode 100644 adapters/stackadapt/stackadapttest/exemplary/simple-web-audio.json create mode 100644 adapters/stackadapt/stackadapttest/exemplary/simple-web-banner.json create mode 100644 adapters/stackadapt/stackadapttest/exemplary/simple-web-native.json create mode 100644 adapters/stackadapt/stackadapttest/exemplary/simple-web-video.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/app-with-existing-publisher.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/auction-price-macro.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/bad-bidder-ext.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/endpoint-param-escaping.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/multi-imp-mismatch.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/native-adm-invalid.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/no-content.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/site-with-existing-publisher.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/status-400.json create mode 100644 adapters/stackadapt/stackadapttest/supplemental/unsupported-mtype.json create mode 100644 openrtb_ext/imp_stackadapt.go create mode 100644 static/bidder-info/stackadapt.yaml create mode 100644 static/bidder-params/stackadapt.json diff --git a/adapters/stackadapt/params_test.go b/adapters/stackadapt/params_test.go new file mode 100644 index 0000000000..25cac9a467 --- /dev/null +++ b/adapters/stackadapt/params_test.go @@ -0,0 +1,60 @@ +package stackadapt + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/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.BidderStackAdapt, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected stackadapt 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.BidderStackAdapt, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId":"pub-123","supplyId":"ssp-1"}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","placementId":"placement-456"}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","banner":{"expdir":[1,3]}}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","bidfloor":1.5}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","placementId":"pl-1","banner":{"expdir":[1,2,3]},"bidfloor":0.5}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `[]`, + `{}`, + `{"placementId":"placement-456"}`, + `{"publisherId":"pub-123"}`, + `{"supplyId":"ssp-1"}`, + `{"publisherId":""}`, + `{"publisherId":"pub-123","supplyId":""}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","bidfloor":-1}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","banner":"invalid"}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","bidfloor":"high"}`, + `{"publisherId":"pub-123","supplyId":"ssp-1","banner":{"expdir":["a"]}}`, +} diff --git a/adapters/stackadapt/stackadapt.go b/adapters/stackadapt/stackadapt.go new file mode 100644 index 0000000000..925a3d7381 --- /dev/null +++ b/adapters/stackadapt/stackadapt.go @@ -0,0 +1,228 @@ +package stackadapt + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "text/template" + + "github.com/buger/jsonparser" + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" + + "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 { + endpoint *template.Template +} + +func Builder(_ openrtb_ext.BidderName, cfg config.Adapter, _ config.Server) (adapters.Bidder, error) { + endpointTemplate, err := template.New("endpointTemplate").Parse(cfg.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %w", err) + } + return &adapter{ + endpoint: endpointTemplate, + }, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + // Imp level + publisherID, supplyID, err := setImpsAndGetEndpointParams(request) + if err != nil { + return nil, []error{err} + } + + // Request level + setPublisherID(request, publisherID) + + endpointURL, err := a.buildEndpointURL(publisherID, supplyID) + if err != nil { + return nil, []error{err} + } + + body, err := jsonutil.Marshal(request) + if err != nil { + return nil, []error{fmt.Errorf("marshal bidRequest: %w", err)} + } + + return []*adapters.RequestData{{ + Method: http.MethodPost, + Uri: endpointURL, + Body: body, + Headers: http.Header{ + "Content-Type": {"application/json;charset=utf-8"}, + "Accept": {"application/json"}, + }, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }}, nil +} + +func (a *adapter) buildEndpointURL(publisherID, supplyID string) (string, error) { + params := macros.EndpointTemplateParams{ + PublisherID: url.QueryEscape(publisherID), + SupplyId: url.QueryEscape(supplyID), + } + return macros.ResolveMacros(a.endpoint, params) +} + +func setImpsAndGetEndpointParams(request *openrtb2.BidRequest) (string, string, error) { + var publisherID, supplyID string + for i, imp := range request.Imp { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return "", "", &errortypes.BadInput{Message: fmt.Sprintf("imp[%d]: unable to unmarshal ext: %s", i, err.Error())} + } + + var saExt openrtb_ext.ExtImpStackAdapt + if err := jsonutil.Unmarshal(bidderExt.Bidder, &saExt); err != nil { + return "", "", &errortypes.BadInput{Message: fmt.Sprintf("imp[%d]: unable to unmarshal bidder ext: %s", i, err.Error())} + } + + if i == 0 { + publisherID = saExt.PublisherId + supplyID = saExt.SupplyId + } else if saExt.PublisherId != publisherID || saExt.SupplyId != supplyID { + return "", "", &errortypes.BadInput{Message: fmt.Sprintf("imp[%d]: all imps must have the same publisherId and supplyId", i)} + } + + if saExt.PlacementId != nil { + request.Imp[i].TagID = *saExt.PlacementId + } + + if saExt.BidFloor > 0 { + request.Imp[i].BidFloor = saExt.BidFloor + request.Imp[i].BidFloorCur = "USD" + } + + if saExt.Banner != nil && len(saExt.Banner.ExpDir) > 0 && request.Imp[i].Banner != nil { + bannerCopy := *request.Imp[i].Banner + bannerCopy.ExpDir = make([]adcom1.ExpandableDirection, len(saExt.Banner.ExpDir)) + for j, dir := range saExt.Banner.ExpDir { + bannerCopy.ExpDir[j] = adcom1.ExpandableDirection(dir) + } + request.Imp[i].Banner = &bannerCopy + } + } + + return publisherID, supplyID, nil +} + +func setPublisherID(request *openrtb2.BidRequest, publisherID string) { + if request.Site != nil { + siteCopy := *request.Site + if siteCopy.Publisher != nil { + publisherCopy := *siteCopy.Publisher + publisherCopy.ID = publisherID + siteCopy.Publisher = &publisherCopy + } else { + siteCopy.Publisher = &openrtb2.Publisher{ID: publisherID} + } + request.Site = &siteCopy + } else if request.App != nil { + appCopy := *request.App + if appCopy.Publisher != nil { + publisherCopy := *appCopy.Publisher + publisherCopy.ID = publisherID + appCopy.Publisher = &publisherCopy + } else { + appCopy.Publisher = &openrtb2.Publisher{ID: publisherID} + } + request.App = &appCopy + } +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + + var errs []error + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, err := getMediaTypeForBid(seatBid.Bid[i]) + if err != nil { + errs = append(errs, err) + continue + } + + if bidType == openrtb_ext.BidTypeNative { + seatBid.Bid[i].AdM, err = getNativeAdm(seatBid.Bid[i].AdM) + if err != nil { + errs = append(errs, err) + continue + } + } + resolveMacros(&seatBid.Bid[i]) + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + + return bidResponse, errs +} + +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.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("unsupported MType %d", bid.MType), + } + } +} + +func resolveMacros(bid *openrtb2.Bid) { + if bid == nil { + return + } + price := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.AdM = strings.ReplaceAll(bid.AdM, "${AUCTION_PRICE}", price) + bid.NURL = strings.ReplaceAll(bid.NURL, "${AUCTION_PRICE}", price) + bid.BURL = strings.ReplaceAll(bid.BURL, "${AUCTION_PRICE}", price) +} + +func getNativeAdm(adm string) (string, error) { + value, dataType, _, err := jsonparser.Get([]byte(adm), string(openrtb_ext.BidTypeNative)) + if err != nil { + if errors.Is(err, jsonparser.KeyPathNotFoundError) { + return adm, nil + } + return adm, errors.New("unable to unmarshal native adm") + } + if dataType != jsonparser.Object { + return adm, errors.New("unable to get native adm") + } + return string(value), nil +} diff --git a/adapters/stackadapt/stackadapt_test.go b/adapters/stackadapt/stackadapt_test.go new file mode 100644 index 0000000000..de323de040 --- /dev/null +++ b/adapters/stackadapt/stackadapt_test.go @@ -0,0 +1,454 @@ +package stackadapt + +import ( + "encoding/json" + "net/http" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +const testsDir = "stackadapttest" +const testsBidderEndpoint = "http://localhost/br?publisher_id={{.PublisherID}}&supply_id={{.SupplyId}}" + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderStackAdapt, + config.Adapter{Endpoint: testsBidderEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, testsDir, bidder) +} + +func TestGetMediaTypeForBid(t *testing.T) { + tests := []struct { + name string + mtype openrtb2.MarkupType + expectedType openrtb_ext.BidType + wantErr bool + }{ + {name: "banner", mtype: 1, expectedType: openrtb_ext.BidTypeBanner}, + {name: "video", mtype: 2, expectedType: openrtb_ext.BidTypeVideo}, + {name: "audio", mtype: 3, expectedType: openrtb_ext.BidTypeAudio}, + {name: "native", mtype: 4, expectedType: openrtb_ext.BidTypeNative}, + {name: "zero", mtype: 0, expectedType: "", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bidType, err := getMediaTypeForBid(openrtb2.Bid{MType: tt.mtype}) + if tt.wantErr { + assert.Error(t, err) + assert.Empty(t, bidType) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expectedType, bidType) + } + }) + } +} + +func TestResolveMacros(t *testing.T) { + tests := []struct { + name string + bid *openrtb2.Bid + expectedAdM string + expectedNURL string + expectedBURL string + }{ + { + name: "nil_bid", + bid: nil, + }, + { + name: "replaces_in_all_fields", + bid: &openrtb2.Bid{ + Price: 2.50, + AdM: "price=${AUCTION_PRICE}", + NURL: "http://win?p=${AUCTION_PRICE}", + BURL: "http://bill?p=${AUCTION_PRICE}", + }, + expectedAdM: "price=2.5", + expectedNURL: "http://win?p=2.5", + expectedBURL: "http://bill?p=2.5", + }, + { + name: "multiple_macros_same_field", + bid: &openrtb2.Bid{ + Price: 1.00, + AdM: "${AUCTION_PRICE}+${AUCTION_PRICE}", + }, + expectedAdM: "1+1", + }, + { + name: "no_macros", + bid: &openrtb2.Bid{ + Price: 5.00, + AdM: "<div>ad</div>", + NURL: "http://example.com", + }, + expectedAdM: "<div>ad</div>", + expectedNURL: "http://example.com", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resolveMacros(tt.bid) + if tt.bid == nil { + return + } + assert.Equal(t, tt.expectedAdM, tt.bid.AdM) + assert.Equal(t, tt.expectedNURL, tt.bid.NURL) + assert.Equal(t, tt.expectedBURL, tt.bid.BURL) + }) + } +} + +func TestGetNativeAdm(t *testing.T) { + tests := []struct { + name string + adm string + expectedAdm string + wantErr bool + }{ + { + name: "unwraps_native_envelope", + adm: `{"native":{"link":{"url":"https://example.com"},"assets":[{"id":1,"title":{"text":"Title"}}]}}`, + expectedAdm: `{"link":{"url":"https://example.com"},"assets":[{"id":1,"title":{"text":"Title"}}]}`, + }, + { + name: "already_unwrapped", + adm: `{"link":{"url":"https://example.com"},"assets":[{"id":1,"title":{"text":"Title"}}]}`, + expectedAdm: `{"link":{"url":"https://example.com"},"assets":[{"id":1,"title":{"text":"Title"}}]}`, + }, + { + name: "no_native_key_passthrough", + adm: `not json`, + expectedAdm: `not json`, + }, + { + name: "malformed_native_envelope", + adm: `{"native":`, + wantErr: true, + }, + { + name: "native_key_not_object", + adm: `{"native":"string_value"}`, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := getNativeAdm(tt.adm) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expectedAdm, result) + } + }) + } +} + +func TestSetPublisherID(t *testing.T) { + t.Run("site_without_publisher", func(t *testing.T) { + req := &openrtb2.BidRequest{Site: &openrtb2.Site{Page: "https://example.com"}} + setPublisherID(req, "pub-1") + assert.Equal(t, "pub-1", req.Site.Publisher.ID) + }) + + t.Run("site_with_existing_publisher", func(t *testing.T) { + req := &openrtb2.BidRequest{Site: &openrtb2.Site{ + Page: "https://example.com", + Publisher: &openrtb2.Publisher{ID: "old", Name: "OldPub"}, + }} + setPublisherID(req, "pub-2") + assert.Equal(t, "pub-2", req.Site.Publisher.ID) + assert.Equal(t, "OldPub", req.Site.Publisher.Name) + }) + + t.Run("app_without_publisher", func(t *testing.T) { + req := &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "com.example"}} + setPublisherID(req, "app-pub-1") + assert.Equal(t, "app-pub-1", req.App.Publisher.ID) + }) + + t.Run("app_with_existing_publisher", func(t *testing.T) { + req := &openrtb2.BidRequest{App: &openrtb2.App{ + Bundle: "com.example", + Publisher: &openrtb2.Publisher{ID: "old", Name: "OldAppPub"}, + }} + setPublisherID(req, "app-pub-2") + assert.Equal(t, "app-pub-2", req.App.Publisher.ID) + assert.Equal(t, "OldAppPub", req.App.Publisher.Name) + }) + + t.Run("site_takes_precedence_over_app", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Site: &openrtb2.Site{Page: "https://example.com"}, + App: &openrtb2.App{Bundle: "com.example"}, + } + setPublisherID(req, "pub-site") + assert.Equal(t, "pub-site", req.Site.Publisher.ID) + assert.Nil(t, req.App.Publisher) + }) + + t.Run("no_site_or_app", func(t *testing.T) { + req := &openrtb2.BidRequest{} + setPublisherID(req, "pub-1") + assert.Nil(t, req.Site) + assert.Nil(t, req.App) + }) +} + +func TestSetImpsAndGetEndpointParams(t *testing.T) { + t.Run("valid_with_all_params", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Banner: &openrtb2.Banner{}, + Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1","placementId":"pl-1","bidfloor":1.5,"banner":{"expdir":[1,3]}}}`), + }}, + } + pubID, supplyID, err := setImpsAndGetEndpointParams(req) + assert.NoError(t, err) + assert.Equal(t, "pub-1", pubID) + assert.Equal(t, "ssp-1", supplyID) + assert.Equal(t, "pl-1", req.Imp[0].TagID) + assert.Equal(t, 1.5, req.Imp[0].BidFloor) + assert.Equal(t, "USD", req.Imp[0].BidFloorCur) + assert.Len(t, req.Imp[0].Banner.ExpDir, 2) + }) + + t.Run("publisher_id_and_supply_id", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-2","supplyId":"ssp-2"}}`), + }}, + } + pubID, supplyID, err := setImpsAndGetEndpointParams(req) + assert.NoError(t, err) + assert.Equal(t, "pub-2", pubID) + assert.Equal(t, "ssp-2", supplyID) + assert.Empty(t, req.Imp[0].TagID) + assert.Zero(t, req.Imp[0].BidFloor) + }) + + t.Run("invalid_ext_json", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Ext: json.RawMessage(`{invalid`), + }}, + } + _, _, err := setImpsAndGetEndpointParams(req) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unable to unmarshal ext") + }) + + t.Run("invalid_bidder_ext_json", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Ext: json.RawMessage(`{"bidder":"not-an-object"}`), + }}, + } + _, _, err := setImpsAndGetEndpointParams(req) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unable to unmarshal bidder ext") + }) + + t.Run("multi_imp_same_publisher_id_and_supply_id", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + {Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1"}}`)}, + {Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1"}}`)}, + }, + } + pubID, supplyID, err := setImpsAndGetEndpointParams(req) + assert.NoError(t, err) + assert.Equal(t, "pub-1", pubID) + assert.Equal(t, "ssp-1", supplyID) + }) + + t.Run("multi_imp_mismatched_publisher_id_or_supply_id", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + {Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1"}}`)}, + {Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-2","supplyId":"ssp-1"}}`)}, + }, + } + _, _, err := setImpsAndGetEndpointParams(req) + assert.Error(t, err) + assert.Contains(t, err.Error(), "all imps must have the same publisherId and supplyId") + }) + + t.Run("zero_bidfloor_not_set", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1","bidfloor":0}}`), + }}, + } + _, _, err := setImpsAndGetEndpointParams(req) + assert.NoError(t, err) + assert.Zero(t, req.Imp[0].BidFloor) + assert.Empty(t, req.Imp[0].BidFloorCur) + }) + + t.Run("expdir_ignored_without_banner", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ + Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1","banner":{"expdir":[1,2]}}}`), + }}, + } + _, _, err := setImpsAndGetEndpointParams(req) + assert.NoError(t, err) + assert.Nil(t, req.Imp[0].Banner) + }) +} + +func TestMakeRequests(t *testing.T) { + a, err := Builder(openrtb_ext.BidderStackAdapt, config.Adapter{Endpoint: testsBidderEndpoint}, config.Server{}) + assert.NoError(t, err) + + t.Run("site_request", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1"}}`)}}, + Site: &openrtb2.Site{Page: "https://example.com"}, + } + data, errs := a.MakeRequests(req, nil) + assert.Empty(t, errs) + assert.Len(t, data, 1) + assert.Equal(t, http.MethodPost, data[0].Method) + assert.Equal(t, "http://localhost/br?publisher_id=pub-1&supply_id=ssp-1", data[0].Uri) + }) + + t.Run("app_request", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Ext: json.RawMessage(`{"bidder":{"publisherId":"pub-1","supplyId":"ssp-1"}}`)}}, + App: &openrtb2.App{Bundle: "com.example"}, + } + data, errs := a.MakeRequests(req, nil) + assert.Empty(t, errs) + assert.Len(t, data, 1) + + var body openrtb2.BidRequest + assert.NoError(t, json.Unmarshal(data[0].Body, &body)) + assert.Equal(t, "pub-1", body.App.Publisher.ID) + assert.Equal(t, "http://localhost/br?publisher_id=pub-1&supply_id=ssp-1", data[0].Uri) + }) + + t.Run("invalid_bidder_ext_returns_error", func(t *testing.T) { + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Ext: json.RawMessage(`{"bidder":"not-an-object"}`)}}, + Site: &openrtb2.Site{}, + } + data, errs := a.MakeRequests(req, nil) + assert.Nil(t, data) + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "unable to unmarshal bidder ext") + }) +} + +func TestBuildEndpointURL(t *testing.T) { + endpointTemplate := "http://localhost/br?publisher_id={{.PublisherID}}&supply_id={{.SupplyId}}" + a, err := Builder(openrtb_ext.BidderStackAdapt, config.Adapter{Endpoint: endpointTemplate}, config.Server{}) + assert.NoError(t, err) + + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Ext: json.RawMessage(`{"bidder":{"publisherId":"test-pub","supplyId":"test-ssp"}}`)}}, + Site: &openrtb2.Site{}, + } + data, errs := a.MakeRequests(req, nil) + assert.Empty(t, errs) + assert.Len(t, data, 1) + assert.Equal(t, "http://localhost/br?publisher_id=test-pub&supply_id=test-ssp", data[0].Uri) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderStackAdapt, config.Adapter{ + Endpoint: "{{Malformed}}", + }, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + assert.Error(t, buildErr) +} + +func TestMakeBids(t *testing.T) { + a, err := Builder(openrtb_ext.BidderStackAdapt, + config.Adapter{Endpoint: testsBidderEndpoint}, config.Server{}) + assert.NoError(t, err) + + t.Run("204_no_content", func(t *testing.T) { + resp, errs := a.MakeBids(nil, nil, &adapters.ResponseData{StatusCode: http.StatusNoContent}) + assert.Nil(t, resp) + assert.Nil(t, errs) + }) + + t.Run("500_server_error", func(t *testing.T) { + resp, errs := a.MakeBids(nil, nil, &adapters.ResponseData{StatusCode: http.StatusInternalServerError}) + assert.Nil(t, resp) + assert.Len(t, errs, 1) + }) + + t.Run("valid_banner_bid", func(t *testing.T) { + resp, errs := a.MakeBids( + &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "imp-1"}}}, + nil, + &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"cur":"USD","seatbid":[{"bid":[{"id":"bid-1","impid":"imp-1","price":1.5,"adm":"<div>ad</div>","mtype":1}]}]}`), + }, + ) + assert.Nil(t, errs) + assert.Len(t, resp.Bids, 1) + assert.Equal(t, openrtb_ext.BidTypeBanner, resp.Bids[0].BidType) + assert.Equal(t, "USD", resp.Currency) + }) + + t.Run("unsupported_mtype_skipped", func(t *testing.T) { + resp, errs := a.MakeBids( + &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "imp-1"}}}, + nil, + &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"seatbid":[{"bid":[{"id":"bid-1","impid":"imp-1","price":1.0,"mtype":99}]}]}`), + }, + ) + assert.Len(t, errs, 1) + assert.Empty(t, resp.Bids) + }) + + t.Run("native_unwrap_and_macro_resolution", func(t *testing.T) { + nativeAdm := `{"native":{"link":{"url":"https://example.com/click"},"assets":[{"id":1,"title":{"text":"Title"}}],"imptrackers":["https://example.com/imp?p=${AUCTION_PRICE}"]}}` + body := `{"seatbid":[{"bid":[{"id":"bid-1","impid":"imp-1","price":3.5,"adm":` + mustMarshalString(nativeAdm) + `,"mtype":4}]}]}` + + resp, errs := a.MakeBids( + &openrtb2.BidRequest{Imp: []openrtb2.Imp{{ID: "imp-1"}}}, + nil, + &adapters.ResponseData{StatusCode: http.StatusOK, Body: []byte(body)}, + ) + assert.Nil(t, errs) + assert.Len(t, resp.Bids, 1) + assert.Equal(t, openrtb_ext.BidTypeNative, resp.Bids[0].BidType) + assert.NotContains(t, resp.Bids[0].Bid.AdM, `"native"`) + assert.NotContains(t, resp.Bids[0].Bid.AdM, "${AUCTION_PRICE}") + }) + + t.Run("invalid_response_body", func(t *testing.T) { + resp, errs := a.MakeBids( + &openrtb2.BidRequest{}, + nil, + &adapters.ResponseData{StatusCode: http.StatusOK, Body: []byte(`not json`)}, + ) + assert.Nil(t, resp) + assert.Len(t, errs, 1) + }) +} + +func mustMarshalString(s string) string { + b, _ := json.Marshal(s) + return string(b) +} diff --git a/adapters/stackadapt/stackadapttest/exemplary/app-banner.json b/adapters/stackadapt/stackadapttest/exemplary/app-banner.json new file mode 100644 index 0000000000..7a4ab2487f --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/app-banner.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }] + }, + "ext": { + "bidder": { + "publisherId": "app-pub-1", + "supplyId": "ssp-1", + "placementId": "app-pl-1" + } + } + }], + "app": { + "bundle": "com.example.app", + "name": "Example App" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=app-pub-1&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }] + }, + "tagid": "app-pl-1", + "ext": { + "bidder": { + "publisherId": "app-pub-1", + "supplyId": "ssp-1", + "placementId": "app-pl-1" + } + } + }], + "app": { + "bundle": "com.example.app", + "name": "Example App", + "publisher": { + "id": "app-pub-1" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.50, + "adm": "<div>mobile-ad</div>", + "crid": "creative-mob-1", + "w": 320, + "h": 50, + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<div>mobile-ad</div>", + "crid": "creative-mob-1", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/exemplary/multi-imp.json b/adapters/stackadapt/stackadapttest/exemplary/multi-imp.json new file mode 100644 index 0000000000..0e721b10c8 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/multi-imp.json @@ -0,0 +1,179 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }, + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1", + "placementId": "pl-1", + "banner": { + "expdir": [1, 3] + }, + "bidfloor": 1.5 + } + } + }, + { + "id": "test-imp-id-2", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2], + "w": 1920, + "h": 1080, + "api": [1, 2] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + } + ], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }, + { + "w": 728, + "h": 90 + } + ], + "expdir": [1, 3] + }, + "tagid": "pl-1", + "bidfloor": 1.5, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1", + "placementId": "pl-1", + "banner": { + "expdir": [1, 3] + }, + "bidfloor": 1.5 + } + } + }, + { + "id": "test-imp-id-2", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2], + "w": 1920, + "h": 1080, + "api": [1, 2] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + } + ], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id", "test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "<div>test-ad</div>", + "adid": "ad-123", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }] + }, + { + "bid": [{ + "id": "test-bid-id-2", + "impid": "test-imp-id-2", + "price": 5.00, + "adm": "<VAST version=\"3.0\"></VAST>", + "crid": "creative-456", + "w": 640, + "h": 480, + "mtype": 2 + }] + } + ] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test-ad</div>", + "adid": "ad-123", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "test-bid-id-2", + "impid": "test-imp-id-2", + "price": 5.00, + "adm": "<VAST version=\"3.0\"></VAST>", + "crid": "creative-456", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/exemplary/simple-web-audio.json b/adapters/stackadapt/stackadapttest/exemplary/simple-web-audio.json new file mode 100644 index 0000000000..3761f08994 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/simple-web-audio.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4", "audio/mpeg", "audio/ogg"], + "minduration": 5, + "maxduration": 30, + "protocols": [3, 6, 2, 5, 7, 8] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/audio" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4", "audio/mpeg", "audio/ogg"], + "minduration": 5, + "maxduration": 30, + "protocols": [3, 6, 2, 5, 7, 8] + }, + "ext": { +"bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/audio", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 4.00, + "adm": "<VAST version=\"2.0\"><Ad id=\"13473443\"><InLine><AdSystem>StackAdapt</AdSystem><Creatives><Creative><Linear><Duration>00:00:14</Duration><MediaFiles><MediaFile type=\"audio/mp4\">https://example.com/audio.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "creative-101", + "mtype": 3 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 4, + "adm": "<VAST version=\"2.0\"><Ad id=\"13473443\"><InLine><AdSystem>StackAdapt</AdSystem><Creatives><Creative><Linear><Duration>00:00:14</Duration><MediaFiles><MediaFile type=\"audio/mp4\">https://example.com/audio.mp4</MediaFile></MediaFiles></Linear></Creative></Creatives></InLine></Ad></VAST>", + "crid": "creative-101", + "mtype": 3 + }, + "type": "audio" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/exemplary/simple-web-banner.json b/adapters/stackadapt/stackadapttest/exemplary/simple-web-banner.json new file mode 100644 index 0000000000..852e1e30b1 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/simple-web-banner.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }, + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1", + "placementId": "pl-1", + "banner": { + "expdir": [1, 3] + }, + "bidfloor": 1.5 + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }, + { + "w": 728, + "h": 90 + } + ], + "expdir": [1, 3] + }, + "tagid": "pl-1", + "bidfloor": 1.5, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1", + "placementId": "pl-1", + "banner": { + "expdir": [1, 3] + }, + "bidfloor": 1.5 + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "<div>test-ad</div>", + "adid": "ad-123", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>test-ad</div>", + "adid": "ad-123", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/exemplary/simple-web-native.json b/adapters/stackadapt/stackadapttest/exemplary/simple-web-native.json new file mode 100644 index 0000000000..0b961d7eac --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/simple-web-native.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":140}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":140}},{\"id\":3,\"required\":1,\"img\":{\"type\":3,\"w\":1200,\"h\":627}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.00, + "adm": "{\"native\":{\"link\":{\"url\":\"https://example.com/click\"},\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}},{\"id\":2,\"img\":{\"url\":\"https://example.com/image.jpg\",\"w\":1200,\"h\":627}}],\"imptrackers\":[\"https://example.com/imp\"]}}", + "crid": "creative-789", + "mtype": 4 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3, + "adm": "{\"link\":{\"url\":\"https://example.com/click\"},\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}},{\"id\":2,\"img\":{\"url\":\"https://example.com/image.jpg\",\"w\":1200,\"h\":627}}],\"imptrackers\":[\"https://example.com/imp\"]}", + "crid": "creative-789", + "mtype": 4 + }, + "type": "native" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/exemplary/simple-web-video.json b/adapters/stackadapt/stackadapttest/exemplary/simple-web-video.json new file mode 100644 index 0000000000..ad7e8d8764 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/exemplary/simple-web-video.json @@ -0,0 +1,94 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2], + "w": 640, + "h": 480, + "api": [1, 2] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/video" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "protocols": [1, 2], + "w": 640, + "h": 480, + "api": [1, 2] + }, + "ext": { +"bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/video", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 5.00, + "adm": "<VAST version=\"3.0\"></VAST>", + "crid": "creative-456", + "w": 640, + "h": 480, + "mtype": 2 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 5, + "adm": "<VAST version=\"3.0\"></VAST>", + "crid": "creative-456", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/supplemental/app-with-existing-publisher.json b/adapters/stackadapt/stackadapttest/supplemental/app-with-existing-publisher.json new file mode 100644 index 0000000000..bccb4ef0d8 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/app-with-existing-publisher.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }] + }, + "ext": { + "bidder": { + "publisherId": "app-pub-new", + "supplyId": "ssp-1" + } + } + }], + "app": { + "bundle": "com.example.app", + "name": "Example App", + "publisher": { + "id": "app-pub-old", + "name": "Existing App Publisher" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=app-pub-new&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 320, + "h": 50 + }] + }, + "ext": { + "bidder": { + "publisherId": "app-pub-new", + "supplyId": "ssp-1" + } + } + }], + "app": { + "bundle": "com.example.app", + "name": "Example App", + "publisher": { + "id": "app-pub-new", + "name": "Existing App Publisher" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<div>app-ad</div>", + "crid": "creative-app-1", + "w": 320, + "h": 50, + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.5, + "adm": "<div>app-ad</div>", + "crid": "creative-app-1", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/auction-price-macro.json b/adapters/stackadapt/stackadapttest/supplemental/auction-price-macro.json new file mode 100644 index 0000000000..2e5316b457 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/auction-price-macro.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.50, + "adm": "<div>ad with price ${AUCTION_PRICE}</div>", + "nurl": "https://example.com/win?price=${AUCTION_PRICE}", + "burl": "https://example.com/billing?price=${AUCTION_PRICE}", + "crid": "creative-macro-1", + "w": 300, + "h": 250, + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.5, + "adm": "<div>ad with price 3.5</div>", + "nurl": "https://example.com/win?price=3.5", + "burl": "https://example.com/billing?price=3.5", + "crid": "creative-macro-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/supplemental/bad-bidder-ext.json b/adapters/stackadapt/stackadapttest/supplemental/bad-bidder-ext.json new file mode 100644 index 0000000000..d0f5d3f218 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/bad-bidder-ext.json @@ -0,0 +1,24 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": "invalid-not-an-object" + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "expectedMakeRequestsErrors": [{ + "value": "imp[0]: unable to unmarshal bidder ext", + "comparison": "startswith" + }] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/supplemental/endpoint-param-escaping.json b/adapters/stackadapt/stackadapttest/supplemental/endpoint-param-escaping.json new file mode 100644 index 0000000000..df261cd7b3 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/endpoint-param-escaping.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub&123", + "supplyId": "ssp 1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub%26123&supply_id=ssp+1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub&123", + "supplyId": "ssp 1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub&123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/multi-imp-mismatch.json b/adapters/stackadapt/stackadapttest/supplemental/multi-imp-mismatch.json new file mode 100644 index 0000000000..d03fc97a0e --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/multi-imp-mismatch.json @@ -0,0 +1,43 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "123", + "supplyId": "ssp-1" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [{ + "w": 728, + "h": 90 + }] + }, + "ext": { + "bidder": { + "publisherId": "456", + "supplyId": "ssp-1" + } + } + } + ], + "site": { + "page": "https://example.com/page" + } + }, + "expectedMakeRequestsErrors": [{ + "value": "imp[1]: all imps must have the same publisherId and supplyId", + "comparison": "literal" + }] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/native-adm-invalid.json b/adapters/stackadapt/stackadapttest/supplemental/native-adm-invalid.json new file mode 100644 index 0000000000..725f69003f --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/native-adm-invalid.json @@ -0,0 +1,74 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\"}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub-123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.1\"}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "{\"native\":\"not-an-object\"}", + "crid": "creative-123", + "mtype": 4 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [] + }], + "expectedMakeBidsErrors": [{ + "value": "unable to get native adm", + "comparison": "literal" + }] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/no-content.json b/adapters/stackadapt/stackadapttest/supplemental/no-content.json new file mode 100644 index 0000000000..90b21a4a38 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/no-content.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub-123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + }], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/stackadapt/stackadapttest/supplemental/site-with-existing-publisher.json b/adapters/stackadapt/stackadapttest/supplemental/site-with-existing-publisher.json new file mode 100644 index 0000000000..1ab79a6338 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/site-with-existing-publisher.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-new", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-old", + "name": "Existing Publisher Name" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub-new&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-new", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-new", + "name": "Existing Publisher Name" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "<div>ad</div>", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "<div>ad</div>", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/status-400.json b/adapters/stackadapt/stackadapttest/supplemental/status-400.json new file mode 100644 index 0000000000..7c8c554391 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/status-400.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub-123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + }], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + }] +} diff --git a/adapters/stackadapt/stackadapttest/supplemental/unsupported-mtype.json b/adapters/stackadapt/stackadapttest/supplemental/unsupported-mtype.json new file mode 100644 index 0000000000..e2a24c7728 --- /dev/null +++ b/adapters/stackadapt/stackadapttest/supplemental/unsupported-mtype.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/br?publisher_id=pub-123&supply_id=ssp-1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": { + "publisherId": "pub-123", + "supplyId": "ssp-1" + } + } + }], + "site": { + "page": "https://example.com/page", + "publisher": { + "id": "pub-123" + } + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.50, + "adm": "some-ad", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 99 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [] + }], + "expectedMakeBidsErrors": [{ + "value": "unsupported MType 99", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 7b722739fd..b5230fd567 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -226,6 +226,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/sovrnXsp" "github.com/prebid/prebid-server/v4/adapters/sparteo" "github.com/prebid/prebid-server/v4/adapters/sspBC" + "github.com/prebid/prebid-server/v4/adapters/stackadapt" "github.com/prebid/prebid-server/v4/adapters/startio" "github.com/prebid/prebid-server/v4/adapters/stroeerCore" "github.com/prebid/prebid-server/v4/adapters/synapseHX" @@ -505,6 +506,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSovrnXsp: sovrnXsp.Builder, openrtb_ext.BidderSparteo: sparteo.Builder, openrtb_ext.BidderSspBC: sspBC.Builder, + openrtb_ext.BidderStackAdapt: stackadapt.Builder, openrtb_ext.BidderStartIO: startio.Builder, openrtb_ext.BidderStroeerCore: stroeerCore.Builder, openrtb_ext.BidderSynapseHX: synapseHX.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 9677e235fe..c1e95e79c6 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -244,6 +244,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSovrnXsp, BidderSparteo, BidderSspBC, + BidderStackAdapt, BidderStartIO, BidderStroeerCore, BidderSynapseHX, @@ -627,6 +628,7 @@ const ( BidderSovrnXsp BidderName = "sovrnXsp" BidderSparteo BidderName = "sparteo" BidderSspBC BidderName = "sspBC" + BidderStackAdapt BidderName = "stackadapt" BidderStartIO BidderName = "startio" BidderStroeerCore BidderName = "stroeerCore" BidderSynapseHX BidderName = "synapseHX" diff --git a/openrtb_ext/imp_stackadapt.go b/openrtb_ext/imp_stackadapt.go new file mode 100644 index 0000000000..930899c2a2 --- /dev/null +++ b/openrtb_ext/imp_stackadapt.go @@ -0,0 +1,13 @@ +package openrtb_ext + +type ExtImpStackAdapt struct { + PublisherId string `json:"publisherId"` + SupplyId string `json:"supplyId"` + PlacementId *string `json:"placementId,omitempty"` + Banner *ExtImpStackAdaptBanner `json:"banner,omitempty"` + BidFloor float64 `json:"bidfloor,omitempty"` +} + +type ExtImpStackAdaptBanner struct { + ExpDir []int `json:"expdir,omitempty"` +} diff --git a/static/bidder-info/stackadapt.yaml b/static/bidder-info/stackadapt.yaml new file mode 100644 index 0000000000..6ba316fe21 --- /dev/null +++ b/static/bidder-info/stackadapt.yaml @@ -0,0 +1,24 @@ +endpoint: "https://pbs.srv.stackadapt.com/br?publisher_id={{.PublisherID}}&supply_id={{.SupplyId}}" +endpointCompression: gzip +maintainer: + email: pjs@stackadapt.com +gvlVendorID: 238 +openrtb: + gpp-supported: true +capabilities: + site: + mediaTypes: + - banner + - video + - native + - audio + app: + mediaTypes: + - banner + - video + - native + - audio +userSync: + redirect: + url: "https://sync.srv.stackadapt.com/sync?nid=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" + userMacro: "$UID" \ No newline at end of file diff --git a/static/bidder-params/stackadapt.json b/static/bidder-params/stackadapt.json new file mode 100644 index 0000000000..68586ce451 --- /dev/null +++ b/static/bidder-params/stackadapt.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "StackAdapt Adapter Params", + "description": "A schema which validates params accepted by the StackAdapt adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "minLength": 1, + "description": "An ID which identifies the publisher, provided by StackAdapt" + }, + "supplyId": { + "type": "string", + "minLength": 1, + "description": "An ID which identifies the supply source, provided by StackAdapt" + }, + "placementId": { + "type": "string", + "minLength": 1, + "description": "An ID which identifies the placement" + }, + "banner": { + "type": "object", + "description": "Banner-specific parameters", + "properties": { + "expdir": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "Expandable ad directions (1=left, 2=right, 3=up, 4=down, 5=fullscreen)" + } + } + }, + "bidfloor": { + "type": "number", + "minimum": 0, + "description": "Bid floor price in USD" + } + }, + "required": ["publisherId", "supplyId"] +} \ No newline at end of file From 64256a7931867f591d8b3b34b15208449cf6cf5c Mon Sep 17 00:00:00 2001 From: tal avital <talavital1993@gmail.com> Date: Tue, 18 Aug 2026 17:31:57 +0300 Subject: [PATCH 259/272] Taboola: Resolve burl macro (#4720) --- adapters/taboola/taboola.go | 23 ++- adapters/taboola/taboola_test.go | 29 +++ .../exemplary/bannerResolveMacro.json | 6 +- .../exemplary/nativeResolveMacro.json | 6 +- .../exemplary/withPageTypeAndPrebidExt.json | 176 ++++++++++++++++++ adapters/taboola/utils.go | 5 - 6 files changed, 229 insertions(+), 16 deletions(-) create mode 100644 adapters/taboola/taboolatest/exemplary/withPageTypeAndPrebidExt.json delete mode 100644 adapters/taboola/utils.go diff --git a/adapters/taboola/taboola.go b/adapters/taboola/taboola.go index ec65a4b677..65b757bf3b 100644 --- a/adapters/taboola/taboola.go +++ b/adapters/taboola/taboola.go @@ -239,7 +239,7 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope } if taboolaExt.PageType != "" { - requestExt, requestExtErr := makeRequestExt(taboolaExt.PageType) + requestExt, requestExtErr := makeRequestExt(taboolaExt.PageType, modifiedRequest.Ext) if requestExtErr == nil { modifiedRequest.Ext = requestExt } else { @@ -253,17 +253,25 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope return taboolaRequests, errs } -func makeRequestExt(pageType string) (json.RawMessage, error) { - requestExt := &RequestExt{ - PageType: pageType, +func makeRequestExt(pageType string, existingExt json.RawMessage) (json.RawMessage, error) { + extMap := make(map[string]json.RawMessage) + if len(existingExt) > 0 { + if err := jsonutil.Unmarshal(existingExt, &extMap); err != nil { + return nil, fmt.Errorf("could not unmarshal request ext: %s", err) + } } - requestExtJson, err := json.Marshal(requestExt) + pageTypeJson, err := jsonutil.Marshal(pageType) if err != nil { - return nil, fmt.Errorf("could not marshal %s, err: %s", requestExt, err) + return nil, fmt.Errorf("could not marshal pageType: %s", err) } - return requestExtJson, nil + extMap["pageType"] = pageTypeJson + requestExtJson, err := jsonutil.Marshal(extMap) + if err != nil { + return nil, fmt.Errorf("could not marshal request ext: %s", err) + } + return requestExtJson, nil } func getMediaType(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { @@ -303,5 +311,6 @@ func resolveMacros(bid *openrtb2.Bid) { price := strconv.FormatFloat(bid.Price, 'f', -1, 64) bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1) bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) + bid.BURL = strings.Replace(bid.BURL, "${AUCTION_PRICE}", price, -1) } } diff --git a/adapters/taboola/taboola_test.go b/adapters/taboola/taboola_test.go index 60004ef1ac..6a5a6ff316 100644 --- a/adapters/taboola/taboola_test.go +++ b/adapters/taboola/taboola_test.go @@ -1,6 +1,7 @@ package taboola import ( + "encoding/json" "testing" "github.com/prebid/prebid-server/v4/adapters/adapterstest" @@ -20,6 +21,34 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "taboolatest", bidder) } +func TestMakeRequestExt(t *testing.T) { + t.Run("merges pageType into existing ext without dropping other fields", func(t *testing.T) { + existingExt := json.RawMessage(`{"prebid":{"integration":"pbjs"}}`) + + result, err := makeRequestExt("article", existingExt) + + assert.NoError(t, err) + assert.JSONEq(t, `{"prebid":{"integration":"pbjs"},"pageType":"article"}`, string(result)) + }) + + t.Run("sets pageType when existing ext is empty", func(t *testing.T) { + result, err := makeRequestExt("article", nil) + + assert.NoError(t, err) + assert.JSONEq(t, `{"pageType":"article"}`, string(result)) + }) + + t.Run("returns error when existing ext is invalid JSON", func(t *testing.T) { + invalidExt := json.RawMessage(`not-a-json-object`) + + result, err := makeRequestExt("article", invalidExt) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "could not unmarshal request ext") + assert.Nil(t, result) + }) +} + func TestEmptyExternalUrl(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.BidderTaboola, config.Adapter{ Endpoint: "http://whatever.com"}, config.Server{}) diff --git a/adapters/taboola/taboolatest/exemplary/bannerResolveMacro.json b/adapters/taboola/taboolatest/exemplary/bannerResolveMacro.json index b673096c0b..f2bf2574c6 100644 --- a/adapters/taboola/taboolatest/exemplary/bannerResolveMacro.json +++ b/adapters/taboola/taboolatest/exemplary/bannerResolveMacro.json @@ -114,7 +114,8 @@ "w": 300, "h": 250, "exp": 60, - "lurl": "https://lurl.domain.com/" + "lurl": "https://lurl.domain.com/", + "burl": "https://burl.domain.com/?wp=${AUCTION_PRICE}" } ], "seat": "1111" @@ -145,7 +146,8 @@ "w": 300, "h": 250, "exp": 60, - "lurl": "https://lurl.domain.com/" + "lurl": "https://lurl.domain.com/", + "burl": "https://burl.domain.com/?wp=2.1" }, "type": "banner" } diff --git a/adapters/taboola/taboolatest/exemplary/nativeResolveMacro.json b/adapters/taboola/taboolatest/exemplary/nativeResolveMacro.json index e30f123cc1..3a25b5688e 100644 --- a/adapters/taboola/taboolatest/exemplary/nativeResolveMacro.json +++ b/adapters/taboola/taboolatest/exemplary/nativeResolveMacro.json @@ -86,7 +86,8 @@ "cid": "cid", "crid": "crid", "lurl": "https://lurl.domain.com/", - "nurl": "nurl.com&wp=${AUCTION_PRICE}" + "nurl": "nurl.com&wp=${AUCTION_PRICE}", + "burl": "https://burl.domain.com/?wp=${AUCTION_PRICE}" } ], "seat": "1111" @@ -116,7 +117,8 @@ "cid": "cid", "crid": "crid", "lurl": "https://lurl.domain.com/", - "nurl": "nurl.com&wp=2.1" + "nurl": "nurl.com&wp=2.1", + "burl": "https://burl.domain.com/?wp=2.1" }, "type": "native" } diff --git a/adapters/taboola/taboolatest/exemplary/withPageTypeAndPrebidExt.json b/adapters/taboola/taboolatest/exemplary/withPageTypeAndPrebidExt.json new file mode 100644 index 0000000000..4c4856e047 --- /dev/null +++ b/adapters/taboola/taboolatest/exemplary/withPageTypeAndPrebidExt.json @@ -0,0 +1,176 @@ +{ + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "publisher-id", + "tagid": "tag-id", + "pageType": "article" + } + } + } + ], + "site": { + "domain": "http://domain.com", + "page": "http://page-domain.com" + }, + "device": { + "ua": "Mozilla/5.0", + "h": 300, + "w": 300 + }, + "ext": { + "prebid": { + "channel": { + "name": "web", + "version": "1.0" + }, + "integration": "pbjs", + "server": { + "externalurl": "https://pbs.example.com", + "gvlid": 42, + "datacenter": "us-east-1" + }, + "sdk": { + "renderers": [ + { + "name": "test-renderer", + "version": "1.0.0" + } + ] + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://display.whatever.com/12/publisher-id", + "body": { + "id": "request-id", + "imp": [ + { + "id": "impression-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "tagid": "tag-id", + "ext": { + "bidder": { + "publisherId": "publisher-id", + "tagid": "tag-id", + "pageType": "article" + } + } + } + ], + "site": { + "id": "publisher-id", + "name": "publisher-id", + "domain": "http://domain.com", + "page": "http://page-domain.com", + "publisher": { + "id": "publisher-id" + } + }, + "device": { + "ua": "Mozilla/5.0", + "h": 300, + "w": 300 + }, + "ext": { + "pageType": "article", + "prebid": { + "channel": { + "name": "web", + "version": "1.0" + }, + "integration": "pbjs", + "server": { + "externalurl": "https://pbs.example.com", + "gvlid": 42, + "datacenter": "us-east-1" + }, + "sdk": { + "renderers": [ + { + "name": "test-renderer", + "version": "1.0.0" + } + ] + } + } + } + }, + "impIDs": ["impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "123", + "seatbid": [ + { + "bid": [ + { + "id": "request-id", + "impid": "impression-id", + "price": 2.1, + "adid": "1", + "adm": "<html></html>", + "adomain": ["adomain.com"], + "cid": "cid", + "crid": "crid", + "w": 300, + "h": 250, + "exp": 60 + } + ], + "seat": "1111" + } + ], + "bidid": "123", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "request-id", + "impid": "impression-id", + "price": 2.1, + "adid": "1", + "adm": "<html></html>", + "adomain": ["adomain.com"], + "cid": "cid", + "crid": "crid", + "w": 300, + "h": 250, + "exp": 60 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/taboola/utils.go b/adapters/taboola/utils.go deleted file mode 100644 index 2703ec69ad..0000000000 --- a/adapters/taboola/utils.go +++ /dev/null @@ -1,5 +0,0 @@ -package taboola - -type RequestExt struct { - PageType string `json:"pageType,omitempty"` -} From f15f9435e152ee2795f30b168bfefd5e58c9cc37 Mon Sep 17 00:00:00 2001 From: Vitali Ioussoupov <84333122+pixfuture-media@users.noreply.github.com> Date: Tue, 18 Aug 2026 10:41:09 -0400 Subject: [PATCH 260/272] New Adapter: Pixfuture (#4715) --- adapters/pixfuture/params_test.go | 71 ++++++ adapters/pixfuture/pixfuture.go | 134 +++++++++++ adapters/pixfuture/pixfuture_test.go | 19 ++ .../pixfuturetest/exemplary/banner-site.json | 113 ++++++++++ .../pixfuturetest/exemplary/multiimp.json | 209 ++++++++++++++++++ .../pixfuturetest/exemplary/native.json | 95 ++++++++ .../pixfuturetest/exemplary/video-app.json | 103 +++++++++ .../pixfuturetest/exemplary/video.json | 97 ++++++++ .../supplemental/bad_status.json | 60 +++++ .../pixfuturetest/supplemental/no_bids.json | 54 +++++ .../supplemental/no_cur_in_response.json | 112 ++++++++++ .../supplemental/status_204.json | 54 +++++ .../supplemental/unknown_type.json | 83 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_pixfuture.go | 5 + static/bidder-info/pixfuture.yaml | 19 ++ static/bidder-params/pixfuture.json | 17 ++ 18 files changed, 1249 insertions(+) create mode 100644 adapters/pixfuture/params_test.go create mode 100644 adapters/pixfuture/pixfuture.go create mode 100644 adapters/pixfuture/pixfuture_test.go create mode 100644 adapters/pixfuture/pixfuturetest/exemplary/banner-site.json create mode 100644 adapters/pixfuture/pixfuturetest/exemplary/multiimp.json create mode 100644 adapters/pixfuture/pixfuturetest/exemplary/native.json create mode 100644 adapters/pixfuture/pixfuturetest/exemplary/video-app.json create mode 100644 adapters/pixfuture/pixfuturetest/exemplary/video.json create mode 100644 adapters/pixfuture/pixfuturetest/supplemental/bad_status.json create mode 100644 adapters/pixfuture/pixfuturetest/supplemental/no_bids.json create mode 100644 adapters/pixfuture/pixfuturetest/supplemental/no_cur_in_response.json create mode 100644 adapters/pixfuture/pixfuturetest/supplemental/status_204.json create mode 100644 adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json create mode 100644 openrtb_ext/imp_pixfuture.go create mode 100644 static/bidder-info/pixfuture.yaml create mode 100644 static/bidder-params/pixfuture.json diff --git a/adapters/pixfuture/params_test.go b/adapters/pixfuture/params_test.go new file mode 100644 index 0000000000..19f2438f65 --- /dev/null +++ b/adapters/pixfuture/params_test.go @@ -0,0 +1,71 @@ +package pixfuture + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema.") + + tests := []struct { + name string + json string + }{ + { + name: "Minimum length satisfied", + json: `{"pix_id": "1"}`, + }, + { + name: "Longer valid string", + json: `{"pix_id": "abcdef"}`, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + assert.NoErrorf(t, validator.Validate(openrtb_ext.BidderPixfuture, json.RawMessage(tt.json)), "Schema rejected valid params: %s", tt.json) + }) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema.") + + tests := []struct { + name string + json string + }{ + { + name: "Wrong type (integer)", + json: `{"pix_id": 123}`, + }, + { + name: "Missing required pix_id", + json: `{}`, + }, + { + name: "Empty string (violates minLength)", + json: `{"pix_id": ""}`, + }, + { + name: "Unknown field (additionalProperties: false)", + json: `{"pix_id": "123", "unknown_field": "anything"}`, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + err := validator.Validate(openrtb_ext.BidderPixfuture, json.RawMessage(tt.json)) + assert.Errorf(t, err, "Schema allowed invalid params: %s", tt.json) + }) + } +} diff --git a/adapters/pixfuture/pixfuture.go b/adapters/pixfuture/pixfuture.go new file mode 100644 index 0000000000..47cebb45a2 --- /dev/null +++ b/adapters/pixfuture/pixfuture.go @@ -0,0 +1,134 @@ +// Package pixfuture implements the Pixfuture adapter for Prebid Server. +// It provides functionality to handle bid requests and responses according to Pixfuture's specifications +package pixfuture + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/iterutil" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{ + endpoint: config.Endpoint, + }, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + + var errs []error + var adapterRequests []*adapters.RequestData + + for imp := range iterutil.SlicePointerValues(request.Imp) { + headers := http.Header{} + headers.Set("Content-Type", "application/json") + headers.Set("Accept", "application/json") + + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{*imp} // slice notation with dereferencing + + reqJSON, err := jsonutil.Marshal(requestCopy) + if err != nil { + errs = append(errs, err) + continue + } + + adapterRequests = append(adapterRequests, &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: []string{imp.ID}, + }) + } + + if len(adapterRequests) == 0 && len(errs) > 0 { + return nil, errs + } + return adapterRequests, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + // Step 1: Check if body is empty to avoid unnecessary unmarshal overhead + if len(response.Body) == 0 { + return nil, nil // Or return a specific error if Pixfuture always expects a body + } + + // Step 2: The Unmarshal call (Lines 88-92) + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Invalid response format: %s", err.Error()), + }} + } + + // Pre-calculate total number of bids // + expectedBids := 0 + for i := range bidResp.SeatBid { + expectedBids += len(bidResp.SeatBid[i].Bid) + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(expectedBids) + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } + + var errs []error + for i := range bidResp.SeatBid { + // Use index j to avoid copying the large openrtb2.Bid struct + for j := range bidResp.SeatBid[i].Bid { + bid := &bidResp.SeatBid[i].Bid[j] + + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errs = append(errs, err) + continue + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + + if len(bidResponse.Bids) == 0 { + return nil, errs + } + + return bidResponse, errs +} + +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 + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse bid mediatype for impression %s from MType", bid.ImpID), + } + } +} diff --git a/adapters/pixfuture/pixfuture_test.go b/adapters/pixfuture/pixfuture_test.go new file mode 100644 index 0000000000..0dfbaf0efa --- /dev/null +++ b/adapters/pixfuture/pixfuture_test.go @@ -0,0 +1,19 @@ +package pixfuture + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderPixfuture, config.Adapter{ + Endpoint: "http://any.url", + }, config.Server{}) + require.NoError(t, buildErr, "Builder returned unexpected error") + + adapterstest.RunJSONBidderTest(t, "pixfuturetest", bidder) +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json b/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json new file mode 100644 index 0000000000..fcbc4ceea5 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": [ + "imp1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/multiimp.json b/adapters/pixfuture/pixfuturetest/exemplary/multiimp.json new file mode 100644 index 0000000000..f89c979cb6 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/multiimp.json @@ -0,0 +1,209 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + }, + { + "id": "imp2", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "pix_id": "55464" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": [ + "imp1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id-1", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad 1</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp2", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "pix_id": "55464" + } + } + } + ] + }, + "impIDs": [ + "imp2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id-2", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid2", + "impid": "imp2", + "price": 2.34, + "adm": "<div>Banner Ad 2</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad 1</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "currency": "USD" + }, + { + "bids": [ + { + "bid": { + "id": "bid2", + "impid": "imp2", + "price": 2.34, + "adm": "<div>Banner Ad 2</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/native.json b/adapters/pixfuture/pixfuturetest/exemplary/native.json new file mode 100644 index 0000000000..9052af00bd --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/native.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":1,\"assets\":[]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":1,\"assets\":[]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "{\"ver\":\"1.2\",\"native\":{\"assets\":[]}}", + "mtype": 4, + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "{\"ver\":\"1.2\",\"native\":{\"assets\":[]}}", + "mtype": 4, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/video-app.json b/adapters/pixfuture/pixfuturetest/exemplary/video-app.json new file mode 100644 index 0000000000..d790349cfa --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/video-app.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "id": "app1" + }, + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "app": { + "id": "app1" + }, + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<vast></vast>", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<vast></vast>", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/video.json b/adapters/pixfuture/pixfuturetest/exemplary/video.json new file mode 100644 index 0000000000..62c0dcd6f8 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/video.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<vast></vast>", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<vast></vast>", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json b/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json new file mode 100644 index 0000000000..4cd7ffb3fd --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 400, + "headers": {}, + "body": "Bad Request" + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json b/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json new file mode 100644 index 0000000000..5f2ccb6748 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 204, + "headers": {}, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/no_cur_in_response.json b/adapters/pixfuture/pixfuturetest/supplemental/no_cur_in_response.json new file mode 100644 index 0000000000..7a1da098bb --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/no_cur_in_response.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": [ + "imp1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Banner Ad</div>", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "currency": "USD" + } + ] +} diff --git a/adapters/pixfuture/pixfuturetest/supplemental/status_204.json b/adapters/pixfuture/pixfuturetest/supplemental/status_204.json new file mode 100644 index 0000000000..5f2ccb6748 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/status_204.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 204, + "headers": {}, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json b/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json new file mode 100644 index 0000000000..e1551cc1c9 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json @@ -0,0 +1,83 @@ +{ + "description": "Tests an unknown bid type response", + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": ["application/json"] + }, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "<div>Ad</div>", + "ext": { + "prebid": { + "type": "unknown" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Failed to parse bid mediatype for impression imp1 from MType", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index b5230fd567..c8da847f76 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -185,6 +185,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/ownadx" "github.com/prebid/prebid-server/v4/adapters/pangle" "github.com/prebid/prebid-server/v4/adapters/pgamssp" + "github.com/prebid/prebid-server/v4/adapters/pixfuture" "github.com/prebid/prebid-server/v4/adapters/playdigo" "github.com/prebid/prebid-server/v4/adapters/proxistore" "github.com/prebid/prebid-server/v4/adapters/pubmatic" @@ -465,6 +466,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderOwnAdx: ownadx.Builder, openrtb_ext.BidderPangle: pangle.Builder, openrtb_ext.BidderPGAMSsp: pgamssp.Builder, + openrtb_ext.BidderPixfuture: pixfuture.Builder, openrtb_ext.BidderPlaydigo: playdigo.Builder, openrtb_ext.BidderProxistore: proxistore.Builder, openrtb_ext.BidderPubmatic: pubmatic.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index c1e95e79c6..4858f69ef8 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -203,6 +203,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderOwnAdx, BidderPangle, BidderPGAMSsp, + BidderPixfuture, BidderPlaydigo, BidderProxistore, BidderPubmatic, @@ -587,6 +588,7 @@ const ( BidderOwnAdx BidderName = "ownadx" BidderPangle BidderName = "pangle" BidderPGAMSsp BidderName = "pgamssp" + BidderPixfuture BidderName = "pixfuture" BidderPlaydigo BidderName = "playdigo" BidderProxistore BidderName = "proxistore" BidderPubmatic BidderName = "pubmatic" diff --git a/openrtb_ext/imp_pixfuture.go b/openrtb_ext/imp_pixfuture.go new file mode 100644 index 0000000000..be8bf36531 --- /dev/null +++ b/openrtb_ext/imp_pixfuture.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtPixfuture struct { + PixID string `json:"pix_id"` +} diff --git a/static/bidder-info/pixfuture.yaml b/static/bidder-info/pixfuture.yaml new file mode 100644 index 0000000000..1f1e78b6b8 --- /dev/null +++ b/static/bidder-info/pixfuture.yaml @@ -0,0 +1,19 @@ +endpoint: "https://pbs-pix.pixfuture.com/pixservices" +maintainer: + email: "client-support@pixfuture.com" +gvlVendorID: 839 +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://sync.pixfuture.com/cookiesync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}" + userMacro: "${UID}" diff --git a/static/bidder-params/pixfuture.json b/static/bidder-params/pixfuture.json new file mode 100644 index 0000000000..ffff62099a --- /dev/null +++ b/static/bidder-params/pixfuture.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "PixFuture Adapter Params", + "description": "A schema which validates params accepted by the PixFuture adapter", + "type": "object", + "properties": { + "pix_id": { + "type": "string", + "description": "PixFuture placement ID", + "minLength": 1 + } + }, + "required": [ + "pix_id" + ], + "additionalProperties": false +} \ No newline at end of file From 4bdb952dfb56d54bcbd6ec8e220a5fb696f191c9 Mon Sep 17 00:00:00 2001 From: nico piderman <nico.piderman@gmail.com> Date: Tue, 18 Aug 2026 16:51:46 +0200 Subject: [PATCH 261/272] AMX: Add currency normalization (#4758) --- adapters/amx/amx.go | 52 +++++- .../amx/amxtest/exemplary/app-simple.json | 5 +- .../amxtest/exemplary/display-multiple.json | 4 +- .../amx/amxtest/exemplary/simple-native.json | 2 +- .../amx/amxtest/exemplary/video-simple.json | 2 +- .../amx/amxtest/exemplary/web-simple.json | 4 +- .../amxtest/supplemental/204-response.json | 2 +- .../amxtest/supplemental/400-response.json | 2 +- .../amxtest/supplemental/500-response.json | 2 +- .../supplemental/bid-floor-no-currency.json | 83 ++++++++++ .../currency-conversion-error.json | 138 ++++++++++++++++ .../currency-conversion-no-cur.json | 152 +++++++++++++++++ .../supplemental/currency-conversion.json | 155 ++++++++++++++++++ 13 files changed, 590 insertions(+), 13 deletions(-) create mode 100644 adapters/amx/amxtest/supplemental/bid-floor-no-currency.json create mode 100644 adapters/amx/amxtest/supplemental/currency-conversion-error.json create mode 100644 adapters/amx/amxtest/supplemental/currency-conversion-no-cur.json create mode 100644 adapters/amx/amxtest/supplemental/currency-conversion.json diff --git a/adapters/amx/amx.go b/adapters/amx/amx.go index e133b16cc2..112717cad0 100644 --- a/adapters/amx/amx.go +++ b/adapters/amx/amx.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "net/url" + "strings" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v4/adapters" @@ -15,7 +16,8 @@ import ( ) const nbrHeaderName = "x-nbr" -const adapterVersion = "pbs1.2" +const adapterVersion = "pbs1.3" +const bidderCurrency = "USD" // AMXAdapter is the AMX bid adapter type AMXAdapter struct { @@ -57,12 +59,41 @@ func ensurePublisherWithID(pub *openrtb2.Publisher, publisherID string) openrtb2 return pubCopy } +func resolveBidFloor(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { + if imp.BidFloor <= 0 || imp.BidFloorCur == "" || strings.EqualFold(imp.BidFloorCur, bidderCurrency) { + return nil + } + + if reqInfo == nil { + return fmt.Errorf("cannot convert bid floor currency %s: reqInfo is nil", imp.BidFloorCur) + } + + convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, bidderCurrency) + if err != nil { + return err + } + + imp.BidFloor = convertedValue + imp.BidFloorCur = bidderCurrency + return nil +} + // MakeRequests creates AMX adapter requests func (adapter *AMXAdapter) MakeRequests(request *openrtb2.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) { reqCopy := *request var publisherID string - for idx, imp := range reqCopy.Imp { + hasBidFloor := false + validImps := make([]openrtb2.Imp, 0, len(reqCopy.Imp)) + for _, imp := range reqCopy.Imp { + if err := resolveBidFloor(&imp, req); err != nil { + errs = append(errs, err) + continue + } + if imp.BidFloor > 0 { + hasBidFloor = true + } + var params amxExt if err := jsonutil.Unmarshal(imp.Ext, ¶ms); err == nil { if params.Bidder.TagID != "" { @@ -72,9 +103,21 @@ func (adapter *AMXAdapter) MakeRequests(request *openrtb2.BidRequest, req *adapt // if it has an adUnitId, set as the tagid if params.Bidder.AdUnitID != "" { imp.TagID = params.Bidder.AdUnitID - reqCopy.Imp[idx] = imp } } + + validImps = append(validImps, imp) + } + + if len(validImps) == 0 { + return nil, errs + } + reqCopy.Imp = validImps + + // bid floors are normalized to USD, so request USD bids to keep the + // response currency consistent with the floors + if hasBidFloor { + reqCopy.Cur = []string{bidderCurrency} } if publisherID != "" { @@ -147,6 +190,9 @@ func (adapter *AMXAdapter) MakeBids(request *openrtb2.BidRequest, externalReques } bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } for _, sb := range bidResp.SeatBid { for _, bid := range sb.Bid { diff --git a/adapters/amx/amxtest/exemplary/app-simple.json b/adapters/amx/amxtest/exemplary/app-simple.json index 1bc205e510..81c3216246 100644 --- a/adapters/amx/amxtest/exemplary/app-simple.json +++ b/adapters/amx/amxtest/exemplary/app-simple.json @@ -64,8 +64,11 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { + "cur": [ + "USD" + ], "app": { "bundle": "639881495", "name": "Imgur (iOS)", diff --git a/adapters/amx/amxtest/exemplary/display-multiple.json b/adapters/amx/amxtest/exemplary/display-multiple.json index 76d97b1704..a14cfcb45c 100644 --- a/adapters/amx/amxtest/exemplary/display-multiple.json +++ b/adapters/amx/amxtest/exemplary/display-multiple.json @@ -98,7 +98,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, @@ -294,4 +294,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/amx/amxtest/exemplary/simple-native.json b/adapters/amx/amxtest/exemplary/simple-native.json index dc158c1a74..a9b23519fa 100644 --- a/adapters/amx/amxtest/exemplary/simple-native.json +++ b/adapters/amx/amxtest/exemplary/simple-native.json @@ -19,7 +19,7 @@ "httpcalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "id": "req_id", "imp": [ diff --git a/adapters/amx/amxtest/exemplary/video-simple.json b/adapters/amx/amxtest/exemplary/video-simple.json index 45e57bf39b..e19a1df15c 100644 --- a/adapters/amx/amxtest/exemplary/video-simple.json +++ b/adapters/amx/amxtest/exemplary/video-simple.json @@ -94,7 +94,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/exemplary/web-simple.json b/adapters/amx/amxtest/exemplary/web-simple.json index 6067243f12..23d5ccc214 100644 --- a/adapters/amx/amxtest/exemplary/web-simple.json +++ b/adapters/amx/amxtest/exemplary/web-simple.json @@ -98,7 +98,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, @@ -244,4 +244,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/amx/amxtest/supplemental/204-response.json b/adapters/amx/amxtest/supplemental/204-response.json index cc5eea2416..bdf0d48472 100644 --- a/adapters/amx/amxtest/supplemental/204-response.json +++ b/adapters/amx/amxtest/supplemental/204-response.json @@ -48,7 +48,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/supplemental/400-response.json b/adapters/amx/amxtest/supplemental/400-response.json index 683bdb8c06..25695233fe 100644 --- a/adapters/amx/amxtest/supplemental/400-response.json +++ b/adapters/amx/amxtest/supplemental/400-response.json @@ -48,7 +48,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/supplemental/500-response.json b/adapters/amx/amxtest/supplemental/500-response.json index 6beefe80b7..d66466de8d 100644 --- a/adapters/amx/amxtest/supplemental/500-response.json +++ b/adapters/amx/amxtest/supplemental/500-response.json @@ -47,7 +47,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.2", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/supplemental/bid-floor-no-currency.json b/adapters/amx/amxtest/supplemental/bid-floor-no-currency.json new file mode 100644 index 0000000000..33c0bb1dcf --- /dev/null +++ b/adapters/amx/amxtest/supplemental/bid-floor-no-currency.json @@ -0,0 +1,83 @@ +{ + "mockBidRequest": { + "id": "no-floor-currency-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 1.5, + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "unused_publisher_id" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", + "body": { + "id": "no-floor-currency-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 1.5, + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "cHJlYmlkLm9yZw" + } + } + }, + "impIDs": [ + "1" + ] + }, + "mockResponse": { + "status": 204, + "headers": { + "X-Nbr": ["3b"] + }, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [] +} diff --git a/adapters/amx/amxtest/supplemental/currency-conversion-error.json b/adapters/amx/amxtest/supplemental/currency-conversion-error.json new file mode 100644 index 0000000000..48fc3e5daf --- /dev/null +++ b/adapters/amx/amxtest/supplemental/currency-conversion-error.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "currency-error-request-id", + "cur": [ + "EUR" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 100, + "bidfloorcur": "JPY", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + }, + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 1, + "bidfloorcur": "GBP", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "unused_publisher_id" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Currency conversion rate not found: 'JPY' => 'USD'", + "comparison": "literal" + } + ], + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", + "body": { + "id": "currency-error-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 2, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "cHJlYmlkLm9yZw" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "impIDs": [ + "2" + ] + }, + "mockResponse": { + "status": 204, + "headers": { + "X-Nbr": ["3b"] + }, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [] +} diff --git a/adapters/amx/amxtest/supplemental/currency-conversion-no-cur.json b/adapters/amx/amxtest/supplemental/currency-conversion-no-cur.json new file mode 100644 index 0000000000..8b0796817e --- /dev/null +++ b/adapters/amx/amxtest/supplemental/currency-conversion-no-cur.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "currency-no-cur-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 1, + "bidfloorcur": "GBP", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "unused_publisher_id" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", + "body": { + "id": "currency-no-cur-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 2, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "cHJlYmlkLm9yZw" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "impIDs": [ + "1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "currency-no-cur-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "TEST", + "impid": "1", + "price": 10, + "adid": "1", + "adm": "<script src=\"https://assets.a-mo.net/tmode.v1.js\"></script>", + "adomain": [ + "amxrtb.com" + ], + "cid": "1", + "crid": "1", + "h": 250, + "w": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "TEST", + "impid": "1", + "price": 10, + "adid": "1", + "adm": "<script src=\"https://assets.a-mo.net/tmode.v1.js\"></script>", + "adomain": [ + "amxrtb.com" + ], + "cid": "1", + "crid": "1", + "h": 250, + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/amx/amxtest/supplemental/currency-conversion.json b/adapters/amx/amxtest/supplemental/currency-conversion.json new file mode 100644 index 0000000000..2bb59ca963 --- /dev/null +++ b/adapters/amx/amxtest/supplemental/currency-conversion.json @@ -0,0 +1,155 @@ +{ + "mockBidRequest": { + "id": "currency-request-id", + "cur": [ + "EUR" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 1, + "bidfloorcur": "GBP", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "unused_publisher_id" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.3", + "body": { + "id": "currency-request-id", + "cur": [ + "USD" + ], + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "bidfloor": 2, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + } + } + ], + "site": { + "domain": "www.example.com", + "publisher": { + "id": "cHJlYmlkLm9yZw" + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 2 + } + }, + "usepbsrates": false + } + } + } + }, + "impIDs": [ + "1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "currency-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "TEST", + "impid": "1", + "price": 10, + "adid": "1", + "adm": "<script src=\"https://assets.a-mo.net/tmode.v1.js\"></script>", + "adomain": [ + "amxrtb.com" + ], + "cid": "1", + "crid": "1", + "h": 250, + "w": 300 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "TEST", + "impid": "1", + "price": 10, + "adid": "1", + "adm": "<script src=\"https://assets.a-mo.net/tmode.v1.js\"></script>", + "adomain": [ + "amxrtb.com" + ], + "cid": "1", + "crid": "1", + "h": 250, + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} From 40605405b3ed9d3f0f2dc824b02200f95825a794 Mon Sep 17 00:00:00 2001 From: Alexander <anode.dev@gmail.com> Date: Tue, 18 Aug 2026 18:53:43 +0300 Subject: [PATCH 262/272] Fix: createModuleStageNamesCollection move added flag into loop (#4772) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- modules/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/helpers.go b/modules/helpers.go index a23f2dc122..66fb40a370 100644 --- a/modules/helpers.go +++ b/modules/helpers.go @@ -12,9 +12,9 @@ var moduleReplacer = strings.NewReplacer(".", "_", "-", "_") func createModuleStageNamesCollection(modules map[string]interface{}) (map[string][]string, error) { moduleStageNameCollector := make(map[string][]string) - var added bool for id, hook := range modules { + added := false if _, ok := hook.(hookstage.Entrypoint); ok { added = true stageName := hooks.StageEntrypoint.String() From 589814a4b752a89fbc7ac45644b67cdc11029847 Mon Sep 17 00:00:00 2001 From: morock <98119227+mo4rock@users.noreply.github.com> Date: Tue, 18 Aug 2026 19:16:25 +0300 Subject: [PATCH 263/272] New Adapter: anzuDSP - xeworks alias (#4810) --- static/bidder-info/anzuDSP.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/anzuDSP.yaml diff --git a/static/bidder-info/anzuDSP.yaml b/static/bidder-info/anzuDSP.yaml new file mode 100644 index 0000000000..c45d33e189 --- /dev/null +++ b/static/bidder-info/anzuDSP.yaml @@ -0,0 +1,9 @@ +aliasOf: "xeworks" +endpoint: "https://rtb.anzu-rtb.live/?pid={{.SourceId}}&host={{.Host}}&pbs=1" +maintainer: + email: "prebid@anzu.io" +userSync: + # anzuDSP supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - redirect From 2cb75c208d70fd0cac900a9e91d11740eb233a73 Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Tue, 18 Aug 2026 19:25:54 +0300 Subject: [PATCH 264/272] New Adapter: m152 (#4816) Co-authored-by: 152media <info@152media.com> --- static/bidder-info/m152.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 static/bidder-info/m152.yaml diff --git a/static/bidder-info/m152.yaml b/static/bidder-info/m152.yaml new file mode 100644 index 0000000000..9c7731b37a --- /dev/null +++ b/static/bidder-info/m152.yaml @@ -0,0 +1,14 @@ +# We have the following regional endpoint domains: 'east' - for US_EAST, 'eu' - for EU +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +aliasOf: "teqblaze" +endpoint: "https://#{REGION}#.152media-ssp.com/pserver" +maintainer: + email: "info@152media.com" +gvlVendorID: 1111 +userSync: + redirect: + url: "https://cs.152media-ssp.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + iframe: + url: "https://cs.152media-ssp.com/pbserverIframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&pbserverUrl={{.RedirectURL}}" + userMacro: "[UID]" From 3e80fa0f63dca59418022af7015927b6daab3a29 Mon Sep 17 00:00:00 2001 From: Mike Hoyt <mike.hoyt@thetradedesk.com> Date: Tue, 18 Aug 2026 10:38:56 -0600 Subject: [PATCH 265/272] TheTradeDesk: openrtb2.6 and audio support (#4824) --- adapters/thetradedesk/thetradedesk.go | 2 + adapters/thetradedesk/thetradedesk_test.go | 8 ++ .../exemplary/simple-audio.json | 109 ++++++++++++++++++ static/bidder-info/thetradedesk.yaml | 3 + 4 files changed, 122 insertions(+) create mode 100644 adapters/thetradedesk/thetradedesktest/exemplary/simple-audio.json diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go index f567b43d9e..46c1cb0649 100644 --- a/adapters/thetradedesk/thetradedesk.go +++ b/adapters/thetradedesk/thetradedesk.go @@ -204,6 +204,8 @@ func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) { return openrtb_ext.BidTypeVideo, nil case openrtb2.MarkupNative: return openrtb_ext.BidTypeNative, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil default: return "", fmt.Errorf("unsupported mtype: %d", markupType) } diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go index 050d64498a..c667850a6b 100644 --- a/adapters/thetradedesk/thetradedesk_test.go +++ b/adapters/thetradedesk/thetradedesk_test.go @@ -100,6 +100,14 @@ func TestGetBidType(t *testing.T) { expectedBidTypeId: openrtb_ext.BidTypeNative, wantErr: false, }, + { + name: "audio", + args: args{ + markupType: openrtb2.MarkupAudio, + }, + expectedBidTypeId: openrtb_ext.BidTypeAudio, + wantErr: false, + }, { name: "invalid", args: args{ diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-audio.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-audio.json new file mode 100644 index 0000000000..6de40fa579 --- /dev/null +++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-audio.json @@ -0,0 +1,109 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "ttd.com" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"] + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://direct.adsrvr.org/bid/bidder/ttd", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "ttd.com", + "publisher": { + "id": "123456" + } + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"] + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-audio", + "ext": { + "prebid": { + "type": "audio" + } + }, + "mtype": 3 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-audio", + "ext": { + "prebid": { + "type": "audio" + } + }, + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} diff --git a/static/bidder-info/thetradedesk.yaml b/static/bidder-info/thetradedesk.yaml index e1354c86dd..3f385d5e85 100644 --- a/static/bidder-info/thetradedesk.yaml +++ b/static/bidder-info/thetradedesk.yaml @@ -8,11 +8,13 @@ capabilities: - banner - video - native + - audio site: mediaTypes: - banner - video - native + - audio userSync: # TheTradeDesk supports user syncing, but requires configuration by the host. Contact a technical account manager # or this bidder directly at the email address in this file to ask about enabling user sync. @@ -21,3 +23,4 @@ userSync: - iframe openrtb: gpp-supported: true + version: 2.6 From 28351b5372e2055c47ca2406b4c1af6575f6570f Mon Sep 17 00:00:00 2001 From: Alexander <anode.dev@gmail.com> Date: Tue, 18 Aug 2026 19:53:28 +0300 Subject: [PATCH 266/272] Scalibur: Fix compression attribute (#4829) Co-authored-by: oleksandr <oleksandr@assertive.ai> --- static/bidder-info/scalibur.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index 8b82f56a3f..06f84058a0 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -1,6 +1,6 @@ endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server" # Leave disabled: false → adapter enabled -compression: gzip +endpointCompression: gzip disabled: false maintainer: email: "support@scalibur.io" From d4064105067b9d61e68b0bc7477ff10ae3f1c136 Mon Sep 17 00:00:00 2001 From: hellena994 <144453361+hellena994@users.noreply.github.com> Date: Tue, 18 Aug 2026 19:07:15 +0200 Subject: [PATCH 267/272] CWire: Support video media format (#4831) Co-authored-by: Milica <110067445+GMilica@users.noreply.github.com> --- adapters/cwire/cwire.go | 18 ++- adapters/cwire/cwire_test.go | 33 ++++ adapters/cwire/cwiretest/exemplary/video.json | 152 ++++++++++++++++++ static/bidder-info/cwire.yaml | 4 +- 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 adapters/cwire/cwiretest/exemplary/video.json diff --git a/adapters/cwire/cwire.go b/adapters/cwire/cwire.go index f0b3fc2088..99deac6b7c 100644 --- a/adapters/cwire/cwire.go +++ b/adapters/cwire/cwire.go @@ -91,12 +91,28 @@ func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.Request bidderResponse.Currency = resp.Cur for _, sb := range resp.SeatBid { for i := range sb.Bid { + bidType, err := getBidType(sb.Bid[i]) + if err != nil { + return nil, []error{err} + } bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ Bid: &sb.Bid[i], - BidType: openrtb_ext.BidTypeBanner, + BidType: bidType, }) } } return bidderResponse, nil } + +func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + // determinate media type by bid response field mtype + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + } + + return "", fmt.Errorf("could not define media type for C Wire impression: %s", bid.ImpID) +} diff --git a/adapters/cwire/cwire_test.go b/adapters/cwire/cwire_test.go index 26b403d202..2e21ef3c6e 100644 --- a/adapters/cwire/cwire_test.go +++ b/adapters/cwire/cwire_test.go @@ -1,11 +1,17 @@ package cwire import ( + "math" + "net/http" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" "github.com/prebid/prebid-server/v4/adapters/adapterstest" "github.com/prebid/prebid-server/v4/config" "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestJsonSamples(t *testing.T) { @@ -27,3 +33,30 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "cwiretest", bidder) } + +func TestMakeRequestsMarshalError(t *testing.T) { + bidder := &adapter{} + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{BidFloor: math.NaN()}}, + } + + requests, errs := bidder.MakeRequests(request, nil) + + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.EqualError(t, errs[0], "Error while encoding OpenRTB BidRequest: json: unsupported value: NaN") +} + +func TestMakeBidsUnknownMarkupType(t *testing.T) { + bidder := &adapter{} + httpResponse := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"seatbid":[{"bid":[{"impid":"imp-1","mtype":0}]}]}`), + } + + response, errs := bidder.MakeBids(nil, nil, httpResponse) + + assert.Nil(t, response) + require.Len(t, errs, 1) + assert.EqualError(t, errs[0], "could not define media type for C Wire impression: imp-1") +} diff --git a/adapters/cwire/cwiretest/exemplary/video.json b/adapters/cwire/cwiretest/exemplary/video.json new file mode 100644 index 0000000000..980522c090 --- /dev/null +++ b/adapters/cwire/cwiretest/exemplary/video.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "cur": [ + "CHF" + ], + "imp": [ + { + "id": "103", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": 15, + "domainId": 42 + } + } + } + ], + "site": { + "page": "http://www.foobar.com/1234.html" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f", + "geo": { + "country": "ch", + "region": "basel-stadt", + "city": "basel" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://cwi.re/prebid/adapter-endpoint", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "cur": [ + "CHF" + ], + "imp": [ + { + "id": "103", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": 15, + "domainId": 42 + } + } + } + ], + "site": { + "page": "http://www.foobar.com/1234.html" + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f", + "geo": { + "country": "ch", + "region": "basel-stadt", + "city": "basel" + } + } + }, + "impIDs": [ + "103" + ] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "cur": "CHF", + "seatbid": [ + { + "seat": "cwire", + "group": 0, + "bid": [ + { + "id": "334", + "impid": "103", + "price": 8.00, + "crid": "9999", + "adm": "<VAST version=\"3.0\"></VAST>", + "w": 640, + "h": 480, + "nurl": "https://embed.cwi.re/delivery/prebid-server/win/334", + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "334", + "impid": "103", + "price": 8.00, + "crid": "9999", + "adm": "<VAST version=\"3.0\"></VAST>", + "w": 640, + "h": 480, + "nurl": "https://embed.cwi.re/delivery/prebid-server/win/334", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/static/bidder-info/cwire.yaml b/static/bidder-info/cwire.yaml index b7a16e05c3..eabe2b61b8 100644 --- a/static/bidder-info/cwire.yaml +++ b/static/bidder-info/cwire.yaml @@ -3,14 +3,16 @@ maintainer: email: "devs@cwire.com" endpointCompression: gzip gvlVendorID: 1081 -modifyingVastXmlAllowed: false +modifyingVastXmlAllowed: true capabilities: app: mediaTypes: - banner + - video site: mediaTypes: - banner + - video userSync: iframe: url: https://prebid.cwi.re/v1/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&rd={{.RedirectURL}} From dd5dc8a94238d8f9d4762ea6f3fb3da6aad19c62 Mon Sep 17 00:00:00 2001 From: cortex-tech <dev@cortextech.it> Date: Tue, 18 Aug 2026 20:17:21 +0300 Subject: [PATCH 268/272] Cortex: Add regional endpoint support (#4832) Co-authored-by: Cortex Dev <dev@cortexch.it> --- static/bidder-info/cortex.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/cortex.yaml b/static/bidder-info/cortex.yaml index 52d811cbc9..e7b5868ea6 100644 --- a/static/bidder-info/cortex.yaml +++ b/static/bidder-info/cortex.yaml @@ -1,5 +1,7 @@ aliasOf: "teqblaze" -endpoint: "https://eu.targetadserver.com/pserver" +# We have the following regional endpoint domains: 'eu' - for EU, 'us-east' - for US_EAST, 'apac' - for APAC +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +endpoint: "https://REGION.targetadserver.com/pserver" maintainer: email: "dev@cortextech.it" capabilities: @@ -11,7 +13,7 @@ capabilities: app: mediaTypes: - banner - - video + - video - native userSync: redirect: From 422d8ac7f5b1683d91f12f94e77fad177917ced7 Mon Sep 17 00:00:00 2001 From: Andrii Rudyk <96918101+And-Rud@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:28:44 +0300 Subject: [PATCH 269/272] New Adapter: Matterfull - Xeworks alias (#4835) Co-authored-by: And-Rud <andrii@xe.works> --- static/bidder-info/matterfull.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 static/bidder-info/matterfull.yaml diff --git a/static/bidder-info/matterfull.yaml b/static/bidder-info/matterfull.yaml new file mode 100644 index 0000000000..80a007a85c --- /dev/null +++ b/static/bidder-info/matterfull.yaml @@ -0,0 +1,9 @@ +aliasOf: "xeworks" +endpoint: "https://rtb.mtflll.com?pid={{.SourceId}}&host={{.Host}}&pbs=1" +maintainer: + email: "adops@bematterfull.com" +userSync: + # matterfull supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - redirect From 64dc388f887b768524594aea93670b3686a5b2da Mon Sep 17 00:00:00 2001 From: Ali Bazlamit <alibazlamit@users.noreply.github.com> Date: Tue, 18 Aug 2026 19:40:54 +0200 Subject: [PATCH 270/272] Fix: Surface PrepareCookieForWrite encoder error (#4841) --- usersync/cookie.go | 2 +- usersync/cookie_test.go | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/usersync/cookie.go b/usersync/cookie.go index 410bece531..deefccced1 100644 --- a/usersync/cookie.go +++ b/usersync/cookie.go @@ -61,7 +61,7 @@ func (cookie *Cookie) PrepareCookieForWrite(cfg *config.HostCookie, encoder Enco for len(cookie.uids) > 0 { encodedCookie, err := encoder.Encode(cookie) if err != nil { - return encodedCookie, nil + return encodedCookie, err } // Convert to HTTP Cookie to Get Size diff --git a/usersync/cookie_test.go b/usersync/cookie_test.go index 6b803591f6..07db4a8763 100644 --- a/usersync/cookie_test.go +++ b/usersync/cookie_test.go @@ -533,6 +533,23 @@ func TestPrepareCookieForWrite(t *testing.T) { } } +type failingEncoder struct{} + +func (failingEncoder) Encode(*Cookie) (string, error) { + return "", errors.New("encode failed") +} + +func TestPrepareCookieForWriteEncoderError(t *testing.T) { + cookie := &Cookie{ + uids: map[string]UIDEntry{ + "adnxs": newTempId("UID", 1), + }, + } + + _, err := cookie.PrepareCookieForWrite(&config.HostCookie{}, failingEncoder{}, nil) + assert.Error(t, err) +} + func TestSyncHostCookie(t *testing.T) { testCases := []struct { name string From 0ba352315253f6692af6497d553cfb12909a1b8b Mon Sep 17 00:00:00 2001 From: prebid-reklamup <prebid@reklamup.com> Date: Tue, 18 Aug 2026 21:07:52 +0300 Subject: [PATCH 271/272] Reklamup: Add GVL vendor ID (#4861) Co-authored-by: Reklamup <support@reklamup.com> Co-authored-by: Vitalii Sumlennyi <vitalii.sumlennyi@teqblaze.com> --- static/bidder-info/reklamup.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/reklamup.yaml b/static/bidder-info/reklamup.yaml index c754ee2d6f..beb03cbcd3 100644 --- a/static/bidder-info/reklamup.yaml +++ b/static/bidder-info/reklamup.yaml @@ -2,6 +2,7 @@ aliasOf: "teqblaze" endpoint: "https://node.reklamup.com/pserver" maintainer: email: "support@reklamup.com" +gvlVendorID: 1619 capabilities: site: mediaTypes: From 8537cb10dc72944e64a287200b0e30a8c8be7b0c Mon Sep 17 00:00:00 2001 From: Brian Sardo <1168933+bsardo@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:21:07 -0400 Subject: [PATCH 272/272] m152: Disable by default (#4921) --- static/bidder-info/m152.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/m152.yaml b/static/bidder-info/m152.yaml index 9c7731b37a..4bc67f075e 100644 --- a/static/bidder-info/m152.yaml +++ b/static/bidder-info/m152.yaml @@ -1,3 +1,4 @@ +disabled: true # We have the following regional endpoint domains: 'east' - for US_EAST, 'eu' - for EU # Please deploy this config in each of your datacenters with the appropriate regional subdomain aliasOf: "teqblaze"