From bc89164de1ea415ccc8d6ff2b5aacdea161e04f2 Mon Sep 17 00:00:00 2001 From: product-trustedstack <141160331+product-trustedstack@users.noreply.github.com> Date: Thu, 2 May 2024 12:45:40 +0530 Subject: [PATCH] New Adapter: Trustedstack (#3618) authored by @product-trustedstack --- adapters/trustedstack/params_test.go | 54 +++++++ adapters/trustedstack/trustedstack.go | 108 ++++++++++++++ adapters/trustedstack/trustedstack_test.go | 31 ++++ .../exemplary/multi-format.json | 84 +++++++++++ .../exemplary/multi-imps.json | 135 ++++++++++++++++++ .../trustedstacktest/exemplary/no-bid.json | 61 ++++++++ .../exemplary/optional-params.json | 63 ++++++++ .../exemplary/simple-banner.json | 101 +++++++++++++ .../exemplary/simple-native.json | 91 ++++++++++++ .../exemplary/simple-video.json | 104 ++++++++++++++ ...valid-req-400-status-code-bad-request.json | 97 +++++++++++++ ...valid-req-500-status-code-bad-request.json | 98 +++++++++++++ ...alid-req-200-incorrect-response-mtype.json | 125 ++++++++++++++++ ...eq-200-bid-response-from-trustedstack.json | 133 +++++++++++++++++ ...lid-req-200-incorrect-response-format.json | 121 ++++++++++++++++ ...id-req-204-response-from-trustedstack.json | 67 +++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_trustedstack.go | 6 + static/bidder-info/trustedstack.yaml | 24 ++++ static/bidder-params/trustedstack.json | 22 +++ 21 files changed, 1529 insertions(+) create mode 100644 adapters/trustedstack/params_test.go create mode 100644 adapters/trustedstack/trustedstack.go create mode 100644 adapters/trustedstack/trustedstack_test.go create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/multi-format.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/multi-imps.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/no-bid.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/optional-params.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/simple-banner.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/simple-native.json create mode 100644 adapters/trustedstack/trustedstacktest/exemplary/simple-video.json create mode 100644 adapters/trustedstack/trustedstacktest/supplemental/invalid-req-400-status-code-bad-request.json create mode 100644 adapters/trustedstack/trustedstacktest/supplemental/invalid-req-500-status-code-bad-request.json create mode 100644 adapters/trustedstack/trustedstacktest/supplemental/ivalid-req-200-incorrect-response-mtype.json create mode 100644 adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-bid-response-from-trustedstack.json create mode 100644 adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-incorrect-response-format.json create mode 100755 adapters/trustedstack/trustedstacktest/supplemental/valid-req-204-response-from-trustedstack.json create mode 100644 openrtb_ext/imp_trustedstack.go create mode 100644 static/bidder-info/trustedstack.yaml create mode 100644 static/bidder-params/trustedstack.json diff --git a/adapters/trustedstack/params_test.go b/adapters/trustedstack/params_test.go new file mode 100644 index 00000000000..55812126cae --- /dev/null +++ b/adapters/trustedstack/params_test.go @@ -0,0 +1,54 @@ +package trustedstack + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/trustedstack.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.BidderTrustedstack, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected trustedstack 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.BidderTrustedstack, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"cid":"123", "crid":"1234"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"cid":"", "crid":""}`, + `{"cid":"only cid is present"}`, + `{"crid":"only crid is present"}`, + `{"ccid":"123","ccrid":"123"}`, + `{"aid":123, "placementId":"123", "siteId":"321"}`, +} diff --git a/adapters/trustedstack/trustedstack.go b/adapters/trustedstack/trustedstack.go new file mode 100644 index 00000000000..f79f43ffe35 --- /dev/null +++ b/adapters/trustedstack/trustedstack.go @@ -0,0 +1,108 @@ +package trustedstack + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + + reqJson, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.endpoint, + Body: reqJson, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }}, nil +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + var errs []error + + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponse() + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bidType, err := getBidMediaTypeFromMtype(&sb.Bid[i]) + if err != nil { + errs = append(errs, err) + } else { + b := &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + } + return bidResponse, errs +} + +// Builder builds a new instance of the Trustedstack adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + url := buildEndpoint(config.Endpoint, server.ExternalUrl) + return &adapter{ + endpoint: url, + }, nil +} + +func getBidMediaTypeFromMtype(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 for imp: %s", bid.ImpID) + } +} + +func buildEndpoint(trustedstackUrl, hostUrl string) string { + + if len(hostUrl) == 0 { + return trustedstackUrl + } + urlObject, err := url.Parse(trustedstackUrl) + if err != nil { + return trustedstackUrl + } + values := urlObject.Query() + values.Add("src", hostUrl) + urlObject.RawQuery = values.Encode() + return urlObject.String() +} diff --git a/adapters/trustedstack/trustedstack_test.go b/adapters/trustedstack/trustedstack_test.go new file mode 100644 index 00000000000..c2e1742c55c --- /dev/null +++ b/adapters/trustedstack/trustedstack_test.go @@ -0,0 +1,31 @@ +package trustedstack + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/prebid/prebid-server/v2/adapters/adapterstest" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderTrustedstack, config.Adapter{ + Endpoint: "https://example.trustedstack.com/rtb/prebid", + ExtraAdapterInfo: "http://localhost:8080/extrnal_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, "trustedstacktest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderTrustedstack, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Nil(t, buildErr) +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/multi-format.json b/adapters/trustedstack/trustedstacktest/exemplary/multi-format.json new file mode 100644 index 00000000000..21d0bb1e520 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/multi-format.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "impIDs": ["1"] + }, + + "mockResponse": { + "status": 204, + "body": "" + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/multi-imps.json b/adapters/trustedstack/trustedstacktest/exemplary/multi-imps.json new file mode 100644 index 00000000000..dc22967dce8 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/multi-imps.json @@ -0,0 +1,135 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + }, + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSESHA", + "crid": "9999999789" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + }, + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSESHA", + "crid": "9999999789" + } + } + } + ] + }, + "impIDs": ["1","2"] + }, + + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "trustedstack", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 50, + "w": 320, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/no-bid.json b/adapters/trustedstack/trustedstacktest/exemplary/no-bid.json new file mode 100644 index 00000000000..195064c807f --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/no-bid.json @@ -0,0 +1,61 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "impIDs":["1"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/optional-params.json b/adapters/trustedstack/trustedstacktest/exemplary/optional-params.json new file mode 100644 index 00000000000..105b5d2981a --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/optional-params.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999", + "tagid_src": "ext" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999", + "tagid_src": "ext" + } + } + } + ] + }, + "impIDs":["1"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/simple-banner.json b/adapters/trustedstack/trustedstacktest/exemplary/simple-banner.json new file mode 100644 index 00000000000..c0fb7519a33 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/simple-banner.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "impIDs":["1"] + }, + + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "trustedstack", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 50, + "w": 320, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 50, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/simple-native.json b/adapters/trustedstack/trustedstacktest/exemplary/simple-native.json new file mode 100644 index 00000000000..7af9ce8eba7 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/simple-native.json @@ -0,0 +1,91 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "native": { + "request": "sample-native-request" + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "native": { + "request": "sample-native-request" + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "impIDs":["1"] + }, + + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "trustedstack", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 50, + "w": 320, + "mtype": 4 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 50, + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/exemplary/simple-video.json b/adapters/trustedstack/trustedstacktest/exemplary/simple-video.json new file mode 100644 index 00000000000..65357342234 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/exemplary/simple-video.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + "impIDs":["1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "trustedstack", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 2.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 480, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 2.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-400-status-code-bad-request.json b/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-400-status-code-bad-request.json new file mode 100644 index 00000000000..7c2cb7c632b --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-400-status-code-bad-request.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "tmax": 1000, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "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": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "some-request-id", + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "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" + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-500-status-code-bad-request.json b/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-500-status-code-bad-request.json new file mode 100644 index 00000000000..6d57a29487e --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/invalid-req-500-status-code-bad-request.json @@ -0,0 +1,98 @@ + +{ + "mockBidRequest": { + "id": "some-request-id", + "tmax": 1000, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "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": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "some-request-id", + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "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/trustedstack/trustedstacktest/supplemental/ivalid-req-200-incorrect-response-mtype.json b/adapters/trustedstack/trustedstacktest/supplemental/ivalid-req-200-incorrect-response-mtype.json new file mode 100644 index 00000000000..0b1dfbb5c66 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/ivalid-req-200-incorrect-response-mtype.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "trustedstack", + "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": 5 + } + ] + } + ], + "bidid": "bid01" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [] + }], + "expectedMakeBidsErrors": [ + { + "value": "unable to fetch mediaType for imp: test-imp-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-bid-response-from-trustedstack.json b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-bid-response-from-trustedstack.json new file mode 100644 index 00000000000..a2388abea37 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-bid-response-from-trustedstack.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "trustedstack", + "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 + } + ] + } + ], + "bidid": "bid01" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "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 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-incorrect-response-format.json b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-incorrect-response-format.json new file mode 100644 index 00000000000..c2cf9a06110 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-200-incorrect-response-format.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "trustedstack", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": "0.500000", + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ], + "bidid": "bid01" + } + } + }], + + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "json: cannot unmarshal string into Go struct field Bid.seatbid.bid.price of type float64", + "comparison": "literal" + } + ] +} diff --git a/adapters/trustedstack/trustedstacktest/supplemental/valid-req-204-response-from-trustedstack.json b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-204-response-from-trustedstack.json new file mode 100755 index 00000000000..39e95277213 --- /dev/null +++ b/adapters/trustedstack/trustedstacktest/supplemental/valid-req-204-response-from-trustedstack.json @@ -0,0 +1,67 @@ +{ + "mockBidRequest": { + "app": { + "bundle": "com.example.app" + }, + "id": "req-id", + "device": { + "ifa": "9d8fe0a9-c0dd-4482-b16b-5709b00c608d", + "ip": "1.1.1.1", + "ua": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36" + }, + "imp": [ + { + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + }, + "banner": { + "w": 320, + "h": 50 + }, + "id": "imp-id" + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.trustedstack.com/rtb/prebid?src=http%3A%2F%2Fhosturl.com", + "body": { + "app": { + "bundle": "com.example.app" + }, + "id": "req-id", + "device": { + "ifa": "9d8fe0a9-c0dd-4482-b16b-5709b00c608d", + "ip": "1.1.1.1", + "ua": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36" + }, + "imp": [ + { + "ext": { + "bidder": { + "cid": "8CUTSTCID", + "crid": "999999999" + } + }, + "banner": { + "w": 320, + "h": 50 + }, + "id": "imp-id" + } + ] + }, + "impIDs": ["imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 9f96cdbf171..486bae21045 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -181,6 +181,7 @@ import ( "github.com/prebid/prebid-server/v2/adapters/trafficgate" "github.com/prebid/prebid-server/v2/adapters/triplelift" "github.com/prebid/prebid-server/v2/adapters/triplelift_native" + "github.com/prebid/prebid-server/v2/adapters/trustedstack" "github.com/prebid/prebid-server/v2/adapters/ucfunnel" "github.com/prebid/prebid-server/v2/adapters/undertone" "github.com/prebid/prebid-server/v2/adapters/unicorn" @@ -391,6 +392,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderTrafficGate: trafficgate.Builder, openrtb_ext.BidderTriplelift: triplelift.Builder, openrtb_ext.BidderTripleliftNative: triplelift_native.Builder, + openrtb_ext.BidderTrustedstack: trustedstack.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 93c6a49e8e4..7a5b0a5cba3 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -199,6 +199,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderTrafficGate, BidderTriplelift, BidderTripleliftNative, + BidderTrustedstack, BidderUcfunnel, BidderUndertone, BidderUnicorn, @@ -485,6 +486,7 @@ const ( BidderTrafficGate BidderName = "trafficgate" BidderTriplelift BidderName = "triplelift" BidderTripleliftNative BidderName = "triplelift_native" + BidderTrustedstack BidderName = "trustedstack" BidderUcfunnel BidderName = "ucfunnel" BidderUndertone BidderName = "undertone" BidderUnicorn BidderName = "unicorn" diff --git a/openrtb_ext/imp_trustedstack.go b/openrtb_ext/imp_trustedstack.go new file mode 100644 index 00000000000..22914929689 --- /dev/null +++ b/openrtb_ext/imp_trustedstack.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ExtImpTrustedstack struct { + Cid string `json:"cid"` + Crid string `json:"crid"` +} diff --git a/static/bidder-info/trustedstack.yaml b/static/bidder-info/trustedstack.yaml new file mode 100644 index 00000000000..ffa48d261d4 --- /dev/null +++ b/static/bidder-info/trustedstack.yaml @@ -0,0 +1,24 @@ +endpoint: "https://prebid-adapter.trustedstack.com/rtb/pb/trustedstacks2s" +extra_info: "https://trustedstack.golang.pbs.com" +maintainer: + email: "product@trustedstack.com" +gvlVendorID: 1288 +endpointCompression: gzip +openrtb: + version: 2.6 +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: https://hb.trustedstack.com/cksync?cs=1&type=pbs&ovsid=setstatuscode&bidder=trustedstack&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: "" \ No newline at end of file diff --git a/static/bidder-params/trustedstack.json b/static/bidder-params/trustedstack.json new file mode 100644 index 00000000000..b52e7bf3f7f --- /dev/null +++ b/static/bidder-params/trustedstack.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Trustedstack Adapter Params", + "description": "A schema which validates params accepted by the Trustedstack adapter", + "type": "object", + "properties": { + "cid": { + "type": "string", + "minLength": 1, + "description": "The customer id provided by Trustedstack." + }, + "crid": { + "type": "string", + "minLength": 1, + "description": "The placement id provided by Trustedstack." + } + }, + "required": [ + "cid", + "crid" + ] +} \ No newline at end of file