diff --git a/adapters/adverxo/adverxo.go b/adapters/adverxo/adverxo.go new file mode 100644 index 00000000000..c76038ebde6 --- /dev/null +++ b/adapters/adverxo/adverxo.go @@ -0,0 +1,226 @@ +package adverxo + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "strconv" + "strings" + "text/template" + + "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" +) + +type adapter struct { + endpointTemplate *template.Template +} + +// Builder builds a new instance of the Adverxo adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + urlTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) + + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &adapter{ + endpointTemplate: urlTemplate, + } + + return bidder, nil +} + +func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var ( + result []*adapters.RequestData + errors []error + ) + + for i := range request.Imp { + imp := request.Imp[i] + + adUnitParams, err := getAdUnitsParams(imp) + if err != nil { + errors = append(errors, err) + continue + } + + endpointUrl, err := adapter.buildEndpointURL(adUnitParams) + if err != nil { + errors = append(errors, err) + continue + } + + err = modifyImp(&imp, requestInfo) + if err != nil { + errors = append(errors, err) + continue + } + + thisRequest := makeRequestCopyWithImp(request, imp) + thisRequestBody, err := json.Marshal(thisRequest) + + if err != nil { + errors = append(errors, err) + continue + } + + result = append(result, &adapters.RequestData{ + Method: "POST", + Uri: endpointUrl, + Body: thisRequestBody, + ImpIDs: []string{imp.ID}, + }) + } + + return result, errors +} + +func (adapter *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.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 := json.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 _, bid := range seatBid.Bid { + bid := bid + bidType, err := getMediaTypeForBid(&bid) + if err != nil { + return nil, []error{err} + } + + // for native bid responses fix Adm field + if bidType == openrtb_ext.BidTypeNative { + bid.AdM, err = getNativeAdm(bid.AdM) + if err != nil { + return nil, []error{err} + } + } + + resolveMacros(&bid) + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + } + + return bidResponse, nil +} + +func getAdUnitsParams(imp openrtb2.Imp) (*openrtb_ext.ImpExtAdverxo, error) { + var ext adapters.ExtImpBidder + + if err := json.Unmarshal(imp.Ext, &ext); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("imp %s: unable to unmarshal ext", imp.ID), + } + } + + var adverxoExt openrtb_ext.ImpExtAdverxo + if err := json.Unmarshal(ext.Bidder, &adverxoExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("imp %s: unable to unmarshal ext.bidder: %v", imp.ID, err), + } + } + + return &adverxoExt, nil +} + +func modifyImp(imp *openrtb2.Imp, requestInfo *adapters.ExtraRequestInfo) error { + if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" { + // Convert to US dollars + convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") + if err != nil { + return err + } + + // Update after conversion. All imp elements inside request.Imp are shallow copies + // therefore, their non-pointer values are not shared memory and are safe to modify. + imp.BidFloorCur = "USD" + imp.BidFloor = convertedValue + } + + return nil +} + +func makeRequestCopyWithImp(request *openrtb2.BidRequest, imp openrtb2.Imp) openrtb2.BidRequest { + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{imp} + + return requestCopy +} + +func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ImpExtAdverxo) (string, error) { + endpointParams := macros.EndpointTemplateParams{ + AdUnit: strconv.Itoa(params.AdUnitId), + TokenID: params.Auth, + } + + return macros.ResolveMacros(adapter.endpointTemplate, endpointParams) +} + +func getMediaTypeForBid(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", bid.MType), + } + } +} + +func getNativeAdm(adm string) (string, error) { + nativeAdm := make(map[string]interface{}) + err := json.Unmarshal([]byte(adm), &nativeAdm) + if err != nil { + return adm, errors.New("unable to unmarshal native adm") + } + + // move bid.adm.native to bid.adm + if _, ok := nativeAdm["native"]; ok { + //using jsonparser to avoid marshaling, encode escape, etc. + value, dataType, _, err := jsonparser.Get([]byte(adm), string(openrtb_ext.BidTypeNative)) + if err != nil || dataType != jsonparser.Object { + return adm, errors.New("unable to get native adm") + } + adm = string(value) + } + + return adm, nil +} + +func resolveMacros(bid *openrtb2.Bid) { + if bid != nil { + price := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) + } +} diff --git a/adapters/adverxo/adverxo_test.go b/adapters/adverxo/adverxo_test.go new file mode 100644 index 00000000000..ca32d50bc3c --- /dev/null +++ b/adapters/adverxo/adverxo_test.go @@ -0,0 +1,28 @@ +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/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdverxo, config.Adapter{ + Endpoint: "https://example.com/auction?id={{.AdUnit}}&auth={{.TokenID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adverxotest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdverxo, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/adverxo/adverxotest/exemplary/banner.json b/adapters/adverxo/adverxotest/exemplary/banner.json new file mode 100644 index 00000000000..8182e9f54a6 --- /dev/null +++ b/adapters/adverxo/adverxotest/exemplary/banner.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=520&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "content", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/exemplary/native.json b/adapters/adverxo/adverxotest/exemplary/native.json new file mode 100644 index 00000000000..325471c30c7 --- /dev/null +++ b/adapters/adverxo/adverxotest/exemplary/native.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 18, + "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=18&auth=fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 18, + "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "{\"native\":{\"assets\":[{\"id\":2,\"title\":{\"text\":\"Title\"}},{\"id\":3,\"data\":{\"value\":\"Description\"}},{\"id\":1,\"img\":{\"url\":\"http://example.com?img\",\"w\":150,\"h\":50}}],\"link\":{\"url\":\"http://example.com?link\"}}}", + "h": 600, + "w": 300, + "mtype": 4 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "{\"assets\":[{\"id\":2,\"title\":{\"text\":\"Title\"}},{\"id\":3,\"data\":{\"value\":\"Description\"}},{\"id\":1,\"img\":{\"url\":\"http://example.com?img\",\"w\":150,\"h\":50}}],\"link\":{\"url\":\"http://example.com?link\"}}", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/exemplary/video.json b/adapters/adverxo/adverxotest/exemplary/video.json new file mode 100644 index 00000000000..046eadc1cde --- /dev/null +++ b/adapters/adverxo/adverxotest/exemplary/video.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "testid", + "imp": [ + { + "id": "testimpid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "adUnitId": 3, + "auth": "qwerty" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/auction?id=3&auth=qwerty", + "body":{ + "id": "testid", + "imp": [{ + "id": "testimpid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "adUnitId": 3, + "auth": "qwerty" + } + } + }] + }, + "impIDs":["testimpid"] + }, + "mockResponse": { + "status": 200, + "body": { + "seatbid": [ + { + "bid": [ + { + "crid": "24080", + "adid": "2068416", + "price": 0.01, + "id": "testid", + "impid": "testimpid", + "cid": "8048", + "mtype": 2 + } + ] + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "crid": "24080", + "adid": "2068416", + "price": 0.01, + "id": "testid", + "impid": "testimpid", + "cid": "8048", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/bad_imp_ext.json b/adapters/adverxo/adverxotest/supplemental/bad_imp_ext.json new file mode 100644 index 00000000000..9c5e16c98e5 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/bad_imp_ext.json @@ -0,0 +1,21 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 320, "h": 50}] + }, + "ext": "badExt" + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "imp test-imp-id: unable to unmarshal ext", + "comparison": "literal" + } + ] +} diff --git a/adapters/adverxo/adverxotest/supplemental/bad_impext_bidder.json b/adapters/adverxo/adverxotest/supplemental/bad_impext_bidder.json new file mode 100644 index 00000000000..c61652f53e6 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/bad_impext_bidder.json @@ -0,0 +1,23 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 320, "h": 50}] + }, + "ext": { + "bidder": "badBidder" + } + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "imp test-imp-id: unable to unmarshal ext.bidder: json: cannot unmarshal string into Go value of type openrtb_ext.ImpExtAdverxo", + "comparison": "literal" + } + ] +} diff --git a/adapters/adverxo/adverxotest/supplemental/currency_conversion.json b/adapters/adverxo/adverxotest/supplemental/currency_conversion.json new file mode 100644 index 00000000000..3562b05e7a8 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/currency_conversion.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "bidfloor": 10.00, + "bidfloorcur": "MXN", + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "MXN": { + "USD": 0.05 + } + }, + "usepbsrates": false + } + } + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/auction?id=520&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "bidfloor": 0.50, + "bidfloorcur": "USD", + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "MXN": { + "USD": 0.05 + } + }, + "usepbsrates": false + } + } + }, + "tmax": 500 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "content", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/currency_rate_not_found.json b/adapters/adverxo/adverxotest/supplemental/currency_rate_not_found.json new file mode 100644 index 00000000000..9bc2ef75fd9 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/currency_rate_not_found.json @@ -0,0 +1,44 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "bidfloor": 1.00, + "bidfloorcur": "JPY", + "ext":{ + "bidder": { + "adUnitId": 18, + "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44" + } + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "MXN": { + "USD": 0.05 + } + }, + "usepbsrates": false + } + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Currency conversion rate not found: 'JPY' => 'USD'", + "comparison": "literal" + } + ] +} diff --git a/adapters/adverxo/adverxotest/supplemental/invalid_mtype.json b/adapters/adverxo/adverxotest/supplemental/invalid_mtype.json new file mode 100644 index 00000000000..5fcdee305fc --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/invalid_mtype.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=520&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported MType 0", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/invalid_native_adm.json b/adapters/adverxo/adverxotest/supplemental/invalid_native_adm.json new file mode 100644 index 00000000000..90694752e57 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/invalid_native_adm.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 18, + "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=18&auth=fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 18, + "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "invalid", + "h": 600, + "w": 300, + "mtype": 4 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + ], + "expectedMakeBidsErrors": [ + { + "value": "unable to unmarshal native adm", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/multi_imps.json b/adapters/adverxo/adverxotest/supplemental/multi_imps.json new file mode 100644 index 00000000000..f5eb56565f0 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/multi_imps.json @@ -0,0 +1,203 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + }, + { + "id": "imp_id2", + "banner": { + "w": 400, + "h": 800 + }, + "ext": { + "bidder": { + "adUnitId": 2, + "auth": "tokenExample2" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/auction?id=1&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "impIDs":["imp_id1"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 600, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id" + } + } + }, + { + "expectedRequest": { + "uri": "https://example.com/auction?id=2&auth=tokenExample2", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id2", + "banner": { + "w": 400, + "h": 800 + }, + "ext": { + "bidder": { + "adUnitId": 2, + "auth": "tokenExample2" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "impIDs":["imp_id2"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id2", + "impid": "imp_id2", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 800, + "w": 400, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + }, + { + "bids": [ + { + "bid": { + "id": "bid_id2", + "impid": "imp_id2", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 400, + "h": 800, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/multiformat.json b/adapters/adverxo/adverxotest/supplemental/multiformat.json new file mode 100644 index 00000000000..06f3be7bd0b --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/multiformat.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=520&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "content", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/no_bid.json b/adapters/adverxo/adverxotest/supplemental/no_bid.json new file mode 100644 index 00000000000..0585f342047 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/no_bid.json @@ -0,0 +1,78 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/auction?id=1&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 204, + "body": "", + "headers": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/resolve_ortb_macro.json b/adapters/adverxo/adverxotest/supplemental/resolve_ortb_macro.json new file mode 100644 index 00000000000..02840ea0d83 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/resolve_ortb_macro.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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": { + "uri": "https://example.com/auction?id=520&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 520, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content prc=${AUCTION_PRICE}", + "h": 600, + "w": 300, + "mtype": 1 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "content prc=1.25", + "crid": "crid", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adverxo/adverxotest/supplemental/server_error.json b/adapters/adverxo/adverxotest/supplemental/server_error.json new file mode 100644 index 00000000000..47d29364f04 --- /dev/null +++ b/adapters/adverxo/adverxotest/supplemental/server_error.json @@ -0,0 +1,82 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/auction?id=1&auth=tokenExample1", + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "adUnitId": 1, + "auth": "tokenExample1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "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" + }, + "tmax": 500 + }, + "impIDs":["imp_id"] + }, + "mockResponse": { + "status": 500, + "body": "", + "headers": {} + } + } + ], + "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/adverxo/params_test.go b/adapters/adverxo/params_test.go new file mode 100644 index 00000000000..a871a03c6e0 --- /dev/null +++ b/adapters/adverxo/params_test.go @@ -0,0 +1,52 @@ +package adverxo + +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.BidderAdverxo, 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.BidderAdverxo, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{ "adUnitId": 5, "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44"}`, + `{ "adUnitId": 402053, "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `{}`, + `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, + `{ "adUnitId": 5}`, + `{ "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44"}`, + `{ "adUnitId": 0, "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44"}`, + `{ "adUnitId": "5", "auth": "fb71a1ec1d4c0b7e3f0a21703fece91d8b65be44"}`, + `{ "adUnitId": 5, "auth": ""}`, + `{ "adUnitId": 5, "auth": "12345"}`, +} diff --git a/adapters/kueezrtb/kueezrtb.go b/adapters/kueezrtb/kueezrtb.go new file mode 100644 index 00000000000..0edfbffd382 --- /dev/null +++ b/adapters/kueezrtb/kueezrtb.go @@ -0,0 +1,132 @@ +package kueezrtb + +import ( + "encoding/json" + "fmt" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" + "net/http" + "net/url" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the kueezrtb 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 requests []*adapters.RequestData + var errors []error + + requestCopy := *request + + for _, imp := range request.Imp { + requestCopy.Imp = []openrtb2.Imp{imp} + + requestJSON, err := json.Marshal(&requestCopy) + if err != nil { + errors = append(errors, fmt.Errorf("marshal bidRequest: %w", err)) + continue + } + + cId, err := extractCid(&imp) + if err != nil { + errors = append(errors, fmt.Errorf("extract cId: %w", err)) + continue + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: fmt.Sprintf("%s%s", a.endpoint, url.QueryEscape(cId)), + Body: requestJSON, + Headers: headers, + ImpIDs: []string{imp.ID}, + } + + requests = append(requests, requestData) + } + + return requests, errors +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + var errs []error + + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", responseData.StatusCode), + }} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("bad server response: %d. ", err), + }} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(response.SeatBid)) + + if response.Cur != "" { + bidResponse.Currency = response.Cur + } + + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errs = append(errs, err) + continue + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + }) + } + } + + return bidResponse, errs +} + +func extractCid(imp *openrtb2.Imp) (string, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return "", fmt.Errorf("unmarshal bidderExt: %w", err) + } + + var impExt openrtb_ext.ImpExtKueez + if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + return "", fmt.Errorf("unmarshal ImpExtkueez: %w", err) + } + return impExt.ConnectionId, 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 + } + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Could not define bid type for imp: %s", bid.ImpID), + } +} diff --git a/adapters/kueezrtb/kueezrtb_test.go b/adapters/kueezrtb/kueezrtb_test.go new file mode 100644 index 00000000000..b62eff292d1 --- /dev/null +++ b/adapters/kueezrtb/kueezrtb_test.go @@ -0,0 +1,24 @@ +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" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderKueezRTB, config.Adapter{ + Endpoint: "http://prebidsrvr.kueezrtb.com/openrtb/", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2", + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "kueezrtbtest", bidder) +} diff --git a/adapters/kueezrtb/kueezrtbtest/exemplary/banner.json b/adapters/kueezrtb/kueezrtbtest/exemplary/banner.json new file mode 100644 index 00000000000..5df7fda99d0 --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/exemplary/banner.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-request-id", + "cur": "", + "bidid": "some-bid-id", + "seatbid": [ + { + "bid": [ + { + "exp": 60, + "adm": "
Some creative
", + "burl": "", + "iurl": "http://prebidsrvr.kueezrtb.com/creative.jpg", + "lurl": "", + "nurl": "", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 400, + "w": 240, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "attr": [], + "cat": [], + "crid": "some-creative-id", + "ext": {}, + "hratio": 0, + "language": "", + "protocol": 0, + "qagmediarating": 0, + "tactic": "", + "wratio": 0, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-impression-id", + "price": 1, + "adm": "
Some creative
", + "adid": "some-ad-id", + "cid": "test", + "iurl": "http://prebidsrvr.kueezrtb.com/creative.jpg", + "crid": "some-creative-id", + "adomain": [ + "test.com" + ], + "dealid": "deal123", + "w": 240, + "h": 400, + "exp": 60, + "ext": {}, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/kueezrtb/kueezrtbtest/exemplary/multi-imp.json b/adapters/kueezrtb/kueezrtbtest/exemplary/multi-imp.json new file mode 100644 index 00000000000..5d71f8670fc --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/exemplary/multi-imp.json @@ -0,0 +1,265 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 1, + "maxduration": 2, + "protocols": [ + 1, + 2, + 5 + ], + "w": 300, + "h": 250, + "startdelay": 1, + "placement": 1, + "playbackmethod": [ + 2 + ], + "api": [ + 1, + 2, + 3, + 4 + ] + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + }, + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 1, + "maxduration": 2, + "protocols": [ + 1, + 2, + 5 + ], + "w": 300, + "h": 250, + "startdelay": 1, + "placement": 1, + "playbackmethod": [ + 2 + ], + "api": [ + 1, + 2, + 3, + 4 + ] + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-request-id", + "cur": "", + "bidid": "some-bid-id", + "seatbid": [ + { + "bid": [ + { + "exp": 60, + "adm": "Some Ad SystemSome Ad Title00:00:02", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 250, + "w": 300, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "crid": "some-creative-id", + "mtype": 2 + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-request-id", + "cur": "", + "bidid": "some-bid-id", + "seatbid": [ + { + "bid": [ + { + "exp": 60, + "adm": "
Some creative
", + "burl": "", + "iurl": "http://prebidsrvr.kueezrtb.com/creative.jpg", + "lurl": "", + "nurl": "", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 400, + "w": 240, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "attr": [], + "cat": [], + "crid": "some-creative-id", + "ext": {}, + "hratio": 0, + "language": "", + "protocol": 0, + "qagmediarating": 0, + "tactic": "", + "wratio": 0, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "exp": 60, + "adm": "Some Ad SystemSome Ad Title00:00:02", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 250, + "w": 300, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "crid": "some-creative-id", + "mtype": 2 + }, + "type": "video" + } + ] + }, + { + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-impression-id", + "price": 1, + "adm": "
Some creative
", + "adid": "some-ad-id", + "cid": "test", + "iurl": "http://prebidsrvr.kueezrtb.com/creative.jpg", + "crid": "some-creative-id", + "adomain": [ + "test.com" + ], + "dealid": "deal123", + "w": 240, + "h": 400, + "exp": 60, + "ext": {}, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/kueezrtb/kueezrtbtest/exemplary/video.json b/adapters/kueezrtb/kueezrtbtest/exemplary/video.json new file mode 100644 index 00000000000..7dc212efdf3 --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/exemplary/video.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 1, + "maxduration": 2, + "protocols": [ + 1, + 2, + 5 + ], + "w": 300, + "h": 250, + "startdelay": 1, + "placement": 1, + "playbackmethod": [ + 2 + ], + "api": [ + 1, + 2, + 3, + 4 + ] + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 1, + "maxduration": 2, + "protocols": [ + 1, + 2, + 5 + ], + "w": 300, + "h": 250, + "startdelay": 1, + "placement": 1, + "playbackmethod": [ + 2 + ], + "api": [ + 1, + 2, + 3, + 4 + ] + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-request-id", + "cur": "", + "bidid": "some-bid-id", + "seatbid": [ + { + "bid": [ + { + "exp": 60, + "adm": "Some Ad SystemSome Ad Title00:00:02", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 250, + "w": 300, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "crid": "some-creative-id", + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "exp": 60, + "adm": "Some Ad SystemSome Ad Title00:00:02", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 250, + "w": 300, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "crid": "some-creative-id", + "mtype": 2 + }, + "type": "video" + } + ] + } + ], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/kueezrtb/kueezrtbtest/supplemental/bad-request.json b/adapters/kueezrtb/kueezrtbtest/supplemental/bad-request.json new file mode 100644 index 00000000000..36656ebe471 --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/supplemental/bad-request.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "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/kueezrtb/kueezrtbtest/supplemental/internal-error.json b/adapters/kueezrtb/kueezrtbtest/supplemental/internal-error.json new file mode 100644 index 00000000000..cd69dc5b26a --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/supplemental/internal-error.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-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/kueezrtb/kueezrtbtest/supplemental/no-content.json b/adapters/kueezrtb/kueezrtbtest/supplemental/no-content.json new file mode 100644 index 00000000000..312fb3e5208 --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/supplemental/no-content.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cid": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/kueezrtb/kueezrtbtest/supplemental/unknown-bid-type.json b/adapters/kueezrtb/kueezrtbtest/supplemental/unknown-bid-type.json new file mode 100644 index 00000000000..61bd2eedf41 --- /dev/null +++ b/adapters/kueezrtb/kueezrtbtest/supplemental/unknown-bid-type.json @@ -0,0 +1,109 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://prebidsrvr.kueezrtb.com/openrtb/test_cid_123", + "body": { + "id": "some-request-id", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 240, + "h": 400 + }, + "ext": { + "bidder": { + "cId": "test_cid_123" + } + } + } + ], + "tmax": 5000 + }, + "impIDs": [ + "some-impression-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-request-id", + "cur": "", + "bidid": "some-bid-id", + "seatbid": [ + { + "bid": [ + { + "exp": 60, + "adm": "
Some creative
", + "burl": "", + "iurl": "http://prebidsrvr.kueezrtb.com/creative.jpg", + "lurl": "", + "nurl": "", + "id": "some-bid-id", + "impid": "some-impression-id", + "h": 400, + "w": 240, + "price": 1, + "dealid": "deal123", + "adomain": [ + "test.com" + ], + "adid": "some-ad-id", + "cid": "test", + "attr": [], + "cat": [], + "crid": "some-creative-id", + "ext": {}, + "hratio": 0, + "language": "", + "protocol": 0, + "qagmediarating": 0, + "tactic": "", + "wratio": 0, + "mtype": 8 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Could not define bid type for imp: some-impression-id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/kueezrtb/params_test.go b/adapters/kueezrtb/params_test.go new file mode 100644 index 00000000000..f7b263728f3 --- /dev/null +++ b/adapters/kueezrtb/params_test.go @@ -0,0 +1,50 @@ +package kueezrtb + +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.BidderKueezRTB, 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 _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderKueezRTB, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"cId": "provided_cid_123"}`, +} + +var invalidParams = []string{ + `{"cId": 123}`, + `{"cId": true}`, + `{"cId": ["array"]}`, + `{"cId": {}`, + `{"cId": ""}`, + `{"cId": null}`, + `{"cId": "provided_cid_123", "extra": "field"}`, + `{"cid": "valid_cid"}`, + `{"cId": "invalid_chars_!@#$%^&*()"}`, +} diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go index ded350b6f00..a1a4083bfc1 100644 --- a/adapters/rubicon/rubicon.go +++ b/adapters/rubicon/rubicon.go @@ -8,8 +8,6 @@ import ( "strconv" "strings" - "github.com/golang-collections/collections/stack" - "github.com/prebid/prebid-server/v3/version" "github.com/prebid/prebid-server/v3/adapters" @@ -404,7 +402,7 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada siteExtRP := rubiconSiteExt{RP: rubiconSiteExtRP{SiteID: int(siteId)}} if siteCopy.Content != nil { siteTarget := make(map[string]interface{}) - updateExtWithIabAndSegtaxAttribute(siteTarget, siteCopy.Content.Data, []int{1, 2, 5, 6}) + updateExtWithIabAttribute(siteTarget, siteCopy.Content.Data, []int{1, 2, 5, 6}) if len(siteTarget) > 0 { updatedSiteTarget, err := json.Marshal(siteTarget) if err != nil { @@ -753,7 +751,7 @@ func updateUserRpTargetWithFpdAttributes(visitor json.RawMessage, user openrtb2. if err != nil { return nil, err } - updateExtWithIabAndSegtaxAttribute(target, user.Data, []int{4}) + updateExtWithIabAttribute(target, user.Data, []int{4}) updatedTarget, err := json.Marshal(target) if err != nil { @@ -762,106 +760,13 @@ func updateUserRpTargetWithFpdAttributes(visitor json.RawMessage, user openrtb2. return updatedTarget, nil } -func updateExtWithIabAndSegtaxAttribute(target map[string]interface{}, data []openrtb2.Data, segTaxes []int) { - taxonomyIdToSegments := getTaxonomyIdToSegments(data) - if len(taxonomyIdToSegments) == 0 { +func updateExtWithIabAttribute(target map[string]interface{}, data []openrtb2.Data, segTaxes []int) { + var segmentIdsToCopy = getSegmentIdsToCopy(data, segTaxes) + if len(segmentIdsToCopy) == 0 { return } - relevantSegments := pickRelevantSegments(taxonomyIdToSegments) - groupedSegments := groupSegments(relevantSegments, segTaxes) - - for key, value := range groupedSegments { - target[key] = value - } -} - -func getTaxonomyIdToSegments(data []openrtb2.Data) map[int]*stack.Stack { - var taxonomyIdToSegments = make(map[int]*stack.Stack) - for _, dataRecord := range data { - if dataRecord.Ext == nil { - continue - } - - var dataRecordExt rubiconDataExt - err := json.Unmarshal(dataRecord.Ext, &dataRecordExt) - if err != nil { - continue - } - - taxonomyId := dataRecordExt.SegTax - originalSegments := dataRecord.Segment - if len(originalSegments) == 0 { - continue - } - - segments, exists := taxonomyIdToSegments[taxonomyId] - if !exists { - segments = stack.New() - taxonomyIdToSegments[taxonomyId] = segments - } - - for _, originalSegment := range originalSegments { - if originalSegment.ID != "" { - segments.Push(originalSegment) - } - } - - if segments.Len() == 0 { - delete(taxonomyIdToSegments, taxonomyId) - } - } - - return taxonomyIdToSegments -} - -func pickRelevantSegments(taxonomyIdToSegments map[int]*stack.Stack) map[int][]string { - var relevantSegments = make(map[int][]string) - taxonomyIds := make([]int, 0) - - for taxonomyId := range taxonomyIdToSegments { - taxonomyIds = append(taxonomyIds, taxonomyId) - } - - i := 0 - consumedSegmentsCount := 0 - for consumedSegmentsCount < 100 && len(taxonomyIds) > 0 { - taxonomyIdIndex := i % len(taxonomyIds) - taxonomyId := taxonomyIds[taxonomyIdIndex] - currentSegments := taxonomyIdToSegments[taxonomyId] - lastSegment := currentSegments.Pop().(openrtb2.Segment) - - if _, exists := relevantSegments[taxonomyId]; !exists { - relevantSegments[taxonomyId] = make([]string, 0) - } - relevantSegments[taxonomyId] = append(relevantSegments[taxonomyId], lastSegment.ID) - consumedSegmentsCount++ - - if currentSegments.Len() == 0 { - taxonomyIds = append(taxonomyIds[:taxonomyIdIndex], taxonomyIds[taxonomyIdIndex+1:]...) - i-- - } - i++ - } - - return relevantSegments -} - -func groupSegments(taxonomyIdToSegmentsIds map[int][]string, segTaxes []int) map[string][]string { - var groupedSegments = make(map[string][]string) - for taxonomyId, segmentsIds := range taxonomyIdToSegmentsIds { - segmentName := "iab" - if !contains(segTaxes, taxonomyId) { - segmentName = "tax" + strconv.Itoa(taxonomyId) - } - - if _, exists := groupedSegments[segmentName]; !exists { - groupedSegments[segmentName] = make([]string, 0) - } - groupedSegments[segmentName] = append(groupedSegments[segmentName], segmentsIds...) - } - - return groupedSegments + target["iab"] = segmentIdsToCopy } func populateFirstPartyDataAttributes(source json.RawMessage, target map[string]interface{}) error { @@ -940,6 +845,26 @@ func mapFromRawJSON(message json.RawMessage) (map[string]interface{}, error) { return targetAsMap, nil } +func getSegmentIdsToCopy(data []openrtb2.Data, segTaxValues []int) []string { + var segmentIdsToCopy = make([]string, 0, len(data)) + + for _, dataRecord := range data { + if dataRecord.Ext != nil { + var dataExtObject rubiconDataExt + err := jsonutil.Unmarshal(dataRecord.Ext, &dataExtObject) + if err != nil { + continue + } + if contains(segTaxValues, dataExtObject.SegTax) { + for _, segment := range dataRecord.Segment { + segmentIdsToCopy = append(segmentIdsToCopy, segment.ID) + } + } + } + } + return segmentIdsToCopy +} + func contains(s []int, e int) bool { for _, a := range s { if a == e { diff --git a/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json b/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json index cc86da97414..52cad5919eb 100644 --- a/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json +++ b/adapters/rubicon/rubicontest/exemplary/25-26-transition-period.json @@ -13,7 +13,44 @@ "pagecat": [ "val1", "val2" - ] + ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + } }, "user": { "yob": 2000, @@ -23,6 +60,60 @@ "lon": -122.346200 }, "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "consent": "consent" } @@ -40,6 +131,7 @@ "ver": "1.0" } } + }, "regs": { "ext": { @@ -102,9 +194,53 @@ "val1", "val2" ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "segmentId1", + "segmentId2", + "segmentId3" + ] + } } }, "publisher": { @@ -116,10 +252,68 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "consent": "consent", "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } @@ -194,9 +388,7 @@ } ] }, - "impIDs": [ - "test-imp-id" - ] + "impIDs":["test-imp-id"] }, "mockResponse": { "status": 200, diff --git a/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json index 1968f209797..8982f95bff5 100644 --- a/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json @@ -46,6 +46,60 @@ "lon": -122.346200 }, "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "data": { "attr1": "val1", @@ -153,6 +207,60 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { @@ -174,6 +282,10 @@ ], "attr5": [ "3" + ], + "iab": [ + "idToCopy", + "idToCopy2" ] } } diff --git a/adapters/rubicon/rubicontest/exemplary/flexible-schema.json b/adapters/rubicon/rubicontest/exemplary/flexible-schema.json index 41bfb47aedf..b9bedd3aa47 100644 --- a/adapters/rubicon/rubicontest/exemplary/flexible-schema.json +++ b/adapters/rubicon/rubicontest/exemplary/flexible-schema.json @@ -46,6 +46,60 @@ "lon": -122.346200 }, "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "data": { "attr1": "val1", @@ -153,6 +207,60 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { @@ -174,6 +282,10 @@ ], "attr5": [ "3" + ], + "iab": [ + "idToCopy", + "idToCopy2" ] } } diff --git a/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json b/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json index bd65b9f5757..2040933b48e 100644 --- a/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json +++ b/adapters/rubicon/rubicontest/exemplary/hardcode-secure.json @@ -13,7 +13,44 @@ "pagecat": [ "val1", "val2" - ] + ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + } }, "user": { "yob": 2000, @@ -22,7 +59,61 @@ "lat": 47.627500, "lon": -122.346200 }, - "gender": "f" + "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -76,9 +167,53 @@ "val1", "val2" ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "segmentId1", + "segmentId2", + "segmentId3" + ] + } } }, "publisher": { @@ -90,9 +225,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } @@ -140,9 +333,7 @@ } ] }, - "impIDs": [ - "test-imp-id" - ] + "impIDs":["test-imp-id"] }, "mockResponse": { "status": 200, diff --git a/adapters/rubicon/rubicontest/exemplary/segtax-attributes.json b/adapters/rubicon/rubicontest/exemplary/segtax-attributes.json deleted file mode 100644 index 526e02c52a1..00000000000 --- a/adapters/rubicon/rubicontest/exemplary/segtax-attributes.json +++ /dev/null @@ -1,501 +0,0 @@ -{ - "mockBidRequest": { - "id": "test-request-id", - "device": { - "ip": "123.123.123.123", - "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "site": { - "pagecat": [ - "val1", - "val2" - ], - "content": { - "data": [ - { - "ext": { - "segtax": 1 - }, - "segment": [ - { - "id": "segmentId1" - }, - { - "id": "segmentId2" - } - ] - }, - { - "ext": { - "segtax": "1" - }, - "segment": [ - { - "id": "shouldNotBeCopied" - } - ] - }, - { - "ext": { - "segtax": 2 - }, - "segment": [ - { - "id": "segmentId3" - } - ] - }, - { - "ext": { - "segtax": 10 - }, - "segment": [ - { - "id": "segmentId4" - } - ] - } - ] - } - }, - "user": { - "yob": 2000, - "geo": { - "country": "USA", - "lat": 47.627500, - "lon": -122.346200 - }, - "gender": "f", - "data": [ - { - "ext": { - "segtax": 4 - }, - "segment": [ - { - "id": "idToCopy" - } - ] - }, - { - "ext": { - "segtax": "someValue" - }, - "segment": [ - { - "id": "shouldNotBeCopied" - } - ] - }, - { - "ext": { - "segtax": "4" - }, - "segment": [ - { - "id": "shouldNotBeCopied2" - } - ] - }, - { - "ext": { - "segtax": 4 - }, - "segment": [ - { - "id": "idToCopy2" - } - ] - }, - { - "ext": { - "segtax": [ - 4 - ] - }, - "segment": [ - { - "id": "shouldNotBeCopied3" - } - ] - }, - { - "ext": { - "segtax": 2 - }, - "segment": [ - { - "id": "idToCopy3" - } - ] - } - ], - "ext": { - "consent": "consent" - } - }, - "source": { - "ext": { - "schain": { - "complete": 0, - "nodes": [ - { - "asi": "asi", - "sid": "sid" - } - ], - "ver": "1.0" - } - } - }, - "regs": { - "ext": { - "gdpr": 1, - "us_privacy": "us_privacy" - } - }, - "imp": [ - { - "id": "test-imp-id", - "instl": 1, - "banner": { - "w": 1024, - "h": 576 - }, - "ext": { - "data": { - "pbadslot": "pbadslot" - }, - "bidder": { - "accountId": 1001, - "siteId": 113932, - "zoneId": 535510, - "pchain": "pchain" - }, - "skadn": { - "version": "1.0", - "sourceapp": "000", - "skadnetlist": { - "max": 0, - "excl": [ - 1 - ], - "addl": [ - "x.skadnetwork" - ] - } - } - } - } - ] - }, - "httpCalls": [ - { - "expectedRequest": { - "uri": "uri?tk_xint=pbs-test-tracker", - "body": { - "id": "test-request-id", - "device": { - "ext": { - "rp": { - "pixelratio": 0 - } - }, - "ip": "123.123.123.123", - "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" - }, - "site": { - "pagecat": [ - "val1", - "val2" - ], - "content": { - "data": [ - { - "ext": { - "segtax": 1 - }, - "segment": [ - { - "id": "segmentId1" - }, - { - "id": "segmentId2" - } - ] - }, - { - "ext": { - "segtax": "1" - }, - "segment": [ - { - "id": "shouldNotBeCopied" - } - ] - }, - { - "ext": { - "segtax": 2 - }, - "segment": [ - { - "id": "segmentId3" - } - ] - }, - { - "ext": { - "segtax": 10 - }, - "segment": [ - { - "id": "segmentId4" - } - ] - } - ] - }, - "ext": { - "rp": { - "site_id": 113932, - "target": { - "iab": [ - "segmentId2", - "segmentId1", - "segmentId3" - ], - "tax10": [ - "segmentId4" - ] - } - } - }, - "publisher": { - "ext": { - "rp": { - "account_id": 1001 - } - } - } - }, - "user": { - "data": [ - { - "ext": { - "segtax": 4 - }, - "segment": [ - { - "id": "idToCopy" - } - ] - }, - { - "ext": { - "segtax": "someValue" - }, - "segment": [ - { - "id": "shouldNotBeCopied" - } - ] - }, - { - "ext": { - "segtax": "4" - }, - "segment": [ - { - "id": "shouldNotBeCopied2" - } - ] - }, - { - "ext": { - "segtax": 4 - }, - "segment": [ - { - "id": "idToCopy2" - } - ] - }, - { - "ext": { - "segtax": [ - 4 - ] - }, - "segment": [ - { - "id": "shouldNotBeCopied3" - } - ] - }, - { - "ext": { - "segtax": 2 - }, - "segment": [ - { - "id": "idToCopy3" - } - ] - } - ], - "ext": { - "consent": "consent", - "rp": { - "target": { - "iab": [ - "idToCopy2", - "idToCopy" - ], - "tax2": [ - "idToCopy3" - ] - } - } - } - }, - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "source": { - "pchain": "pchain", - "ext": { - "schain": { - "complete": 0, - "nodes": [ - { - "asi": "asi", - "sid": "sid" - } - ], - "ver": "1.0" - } - } - }, - "regs": { - "ext": { - "gdpr": 1, - "us_privacy": "us_privacy" - } - }, - "imp": [ - { - "id": "test-imp-id", - "instl": 1, - "secure": 1, - "banner": { - "ext": { - "rp": { - "mime": "text/html" - } - }, - "w": 1024, - "h": 576 - }, - "ext": { - "rp": { - "target": { - "pbadslot": "pbadslot", - "pbs_login": "xuser", - "pbs_url": "http://hosturl.com", - "pbs_version": "" - }, - "track": { - "mint": "", - "mint_version": "" - }, - "zone_id": 535510 - }, - "skadn": { - "skadnetlist": { - "max": 0, - "excl": [ - 1 - ], - "addl": [ - "x.skadnetwork" - ] - }, - "sourceapp": "000", - "version": "1.0" - } - } - } - ] - }, - "impIDs": [ - "test-imp-id" - ] - }, - "mockResponse": { - "status": 200, - "body": { - "id": "test-request-id", - "seatbid": [ - { - "buyer": "123", - "bid": [ - { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "some-test-ad", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "ext": { - "prebid": { - "meta": { - "networkId": 123 - }, - "type": "banner" - } - } - } - ], - "seat": "adman" - } - ], - "cur": "USD" - } - } - } - ], - "expectedBidResponses": [ - { - "currency": "USD", - "bids": [ - { - "bid": { - "id": "test_bid_id", - "impid": "test-imp-id", - "price": 0.27543, - "adm": "some-test-ad", - "cid": "test_cid", - "crid": "test_crid", - "dealid": "test_dealid", - "ext": { - "prebid": { - "meta": { - "networkId": 123 - }, - "type": "banner" - } - } - }, - "type": "banner" - } - ] - } - ] -} diff --git a/adapters/rubicon/rubicontest/exemplary/simple-banner.json b/adapters/rubicon/rubicontest/exemplary/simple-banner.json index e1d2c63b78e..86663034adb 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-banner.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-banner.json @@ -13,7 +13,44 @@ "pagecat": [ "val1", "val2" - ] + ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + } }, "user": { "yob": 2000, @@ -23,7 +60,61 @@ "lon": -122.346200 }, "gender": "f", - "consent": "consent" + "consent": "consent", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -80,9 +171,53 @@ "val1", "val2" ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "segmentId1", + "segmentId2", + "segmentId3" + ] + } } }, "publisher": { @@ -94,10 +229,68 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "consent": "consent", "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/rubicon/rubicontest/exemplary/simple-native.json b/adapters/rubicon/rubicontest/exemplary/simple-native.json index 34f24d55c8d..576faecbee4 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-native.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-native.json @@ -13,7 +13,44 @@ "pagecat": [ "val1", "val2" - ] + ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + } }, "user": { "yob": 2000, @@ -22,7 +59,61 @@ "lat": 47.627500, "lon": -122.346200 }, - "gender": "f" + "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -67,9 +158,53 @@ "val1", "val2" ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "segmentId1", + "segmentId2", + "segmentId3" + ] + } } }, "publisher": { @@ -81,9 +216,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json index 5f5212be2b8..ccdfab1699c 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-video.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json @@ -13,7 +13,44 @@ "pagecat": [ "val1", "val2" - ] + ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + } }, "user": { "yob": 2000, @@ -22,7 +59,61 @@ "lat": 47.627500, "lon": -122.346200 }, - "gender": "f" + "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -76,9 +167,53 @@ "val1", "val2" ], + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "segmentId1" + }, + { + "id": "segmentId2" + } + ] + }, + { + "ext": { + "segtax": "1" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "segmentId3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "segmentId1", + "segmentId2", + "segmentId3" + ] + } } }, "publisher": { @@ -90,9 +225,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json index ab42f481c66..9a8468ce15a 100644 --- a/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json @@ -39,6 +39,82 @@ ], "attr7": 1.23 } + }, + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "2" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": 5 + }, + "segment": [ + { + "id": "idToCopy3" + } + ] + }, + { + "ext": { + "segtax": 6 + }, + "segment": [ + { + "id": "idToCopy4" + } + ] + }, + { + "ext": { + "segtax": [ + 2 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] } }, "user": { @@ -48,7 +124,61 @@ "lat": 47.627500, "lon": -122.346200 }, - "gender": "f" + "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -113,9 +243,93 @@ "page": "somePage", "ref": "someRef", "search": "someSearch", + "content": { + "data": [ + { + "ext": { + "segtax": 1 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "2" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 2 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": 5 + }, + "segment": [ + { + "id": "idToCopy3" + } + ] + }, + { + "ext": { + "segtax": 6 + }, + "segment": [ + { + "id": "idToCopy4" + } + ] + }, + { + "ext": { + "segtax": [ + 2 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] + }, "ext": { "rp": { - "site_id": 113932 + "site_id": 113932, + "target": { + "iab": [ + "idToCopy", + "idToCopy2", + "idToCopy3", + "idToCopy4" + ] + } } }, "publisher": { @@ -127,9 +341,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/rubicon/rubicontest/exemplary/user-fpd.json b/adapters/rubicon/rubicontest/exemplary/user-fpd.json index f685e5581e8..a03234d48d4 100644 --- a/adapters/rubicon/rubicontest/exemplary/user-fpd.json +++ b/adapters/rubicon/rubicontest/exemplary/user-fpd.json @@ -18,6 +18,60 @@ "lon": -122.346200 }, "gender": "f", + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "keywords": "someKeywords", "ext": { "rp": { @@ -104,6 +158,60 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { @@ -117,6 +225,10 @@ ], "dataKey3": [ "true" + ], + "iab": [ + "idToCopy", + "idToCopy2" ] } } diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json index a51bfa09097..b7d8f84287b 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json @@ -18,6 +18,60 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -83,9 +137,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content.json b/adapters/rubicon/rubicontest/supplemental/no-site-content.json index b4f143978e1..bcdd9acb9a2 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content.json @@ -16,6 +16,60 @@ ] }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ] }, "imp": [ { @@ -79,9 +133,67 @@ } }, "user": { + "data": [ + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy" + } + ] + }, + { + "ext": { + "segtax": "someValue" + }, + "segment": [ + { + "id": "shouldNotBeCopied" + } + ] + }, + { + "ext": { + "segtax": "4" + }, + "segment": [ + { + "id": "shouldNotBeCopied2" + } + ] + }, + { + "ext": { + "segtax": 4 + }, + "segment": [ + { + "id": "idToCopy2" + } + ] + }, + { + "ext": { + "segtax": [ + 4 + ] + }, + "segment": [ + { + "id": "shouldNotBeCopied3" + } + ] + } + ], "ext": { "rp": { "target": { + "iab": [ + "idToCopy", + "idToCopy2" + ] } } } diff --git a/adapters/sovrn/params_test.go b/adapters/sovrn/params_test.go new file mode 100644 index 00000000000..021043c1c64 --- /dev/null +++ b/adapters/sovrn/params_test.go @@ -0,0 +1,53 @@ +package sovrn + +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 json-schemas. %v", err) + } + + for _, param := range validParams { + if err := validator.Validate(openrtb_ext.BidderSovrn, json.RawMessage(param)); err != nil { + t.Errorf("Schema rejected sovrn 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.BidderSovrn, json.RawMessage(param)); err == nil { + t.Errorf("Schema allowed sovrn params: %s", param) + } + } +} + +var validParams = []string{ + `{"tagId":"1"}`, + `{"tagid":"2"}`, + `{"tagId":"1","bidfloor":"0.5"}`, + `{"tagId":"1","bidfloor":0.5}`, + `{"tagId":"1","bidfloor":"0.5", "adunitcode":"0.5"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `0`, + `[]`, + `{}`, +} diff --git a/adapters/sovrn/sovrn.go b/adapters/sovrn/sovrn.go index ea28891883d..91ca9d3ce12 100644 --- a/adapters/sovrn/sovrn.go +++ b/adapters/sovrn/sovrn.go @@ -76,8 +76,9 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt imp.TagID = tagId - if imp.BidFloor == 0 && sovrnExt.BidFloor > 0 { - imp.BidFloor = sovrnExt.BidFloor + extBidFloor := getExtBidFloor(sovrnExt) + if imp.BidFloor == 0 && extBidFloor > 0 { + imp.BidFloor = extBidFloor } var impExtBuffer []byte @@ -191,6 +192,18 @@ func (s *SovrnAdapter) MakeBids(request *openrtb2.BidRequest, bidderRequest *ada return response, errs } +func getExtBidFloor(sovrnExt openrtb_ext.ExtImpSovrn) float64 { + switch v := sovrnExt.BidFloor.(type) { + case string: + if numValue, err := strconv.ParseFloat(v, 64); err == nil { + return numValue + } + case float64: + return v + } + return 0 +} + func getTagId(sovrnExt openrtb_ext.ExtImpSovrn) string { if len(sovrnExt.Tagid) > 0 { return sovrnExt.Tagid diff --git a/adapters/sovrn/sovrntest/supplemental/custom-overrides-default-bidfloor.json b/adapters/sovrn/sovrntest/supplemental/custom-overrides-default-bidfloor.json new file mode 100644 index 00000000000..a74367be61f --- /dev/null +++ b/adapters/sovrn/sovrntest/supplemental/custom-overrides-default-bidfloor.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "bidfloor": 0, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.20" + } + } + } + ], + "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", + "bidfloor": 4.2, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.20" + } + } + } + ], + "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" + } + ] + } + ] +} diff --git a/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-as-string.json b/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-as-string.json new file mode 100644 index 00000000000..6e9d87b0ce7 --- /dev/null +++ b/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-as-string.json @@ -0,0 +1,126 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.2" + } + } + } + ], + "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", + "bidfloor": 4.2, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.2" + } + } + } + ], + "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" + } + ] + } + ] +} diff --git a/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-erroneus.json b/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-erroneus.json new file mode 100644 index 00000000000..5f651eb6157 --- /dev/null +++ b/adapters/sovrn/sovrntest/supplemental/only-custom-bidfloor-erroneus.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "err" + } + } + } + ], + "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", + "bidfloor": "err" + } + } + } + ], + "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" + } + ] + } + ] +} diff --git a/adapters/sovrn/sovrntest/supplemental/with-both-custom-default-bidfloor-as-string.json b/adapters/sovrn/sovrntest/supplemental/with-both-custom-default-bidfloor-as-string.json new file mode 100644 index 00000000000..f68e0432cca --- /dev/null +++ b/adapters/sovrn/sovrntest/supplemental/with-both-custom-default-bidfloor-as-string.json @@ -0,0 +1,127 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "bidfloor": 1.69, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.20" + } + } + } + ], + "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", + "bidfloor": 1.69, + "ext": { + "bidder": { + "tagid": "123456", + "bidfloor": "4.20" + } + } + } + ], + "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" + } + ] + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 55355bb1626..4da26e23152 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -29,6 +29,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/adtonos" "github.com/prebid/prebid-server/v3/adapters/adtrgtme" "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" @@ -123,6 +124,7 @@ import ( "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" @@ -263,6 +265,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdtelligent: adtelligent.Builder, openrtb_ext.BidderAdTonos: adtonos.Builder, openrtb_ext.BidderAdvangelists: advangelists.Builder, + openrtb_ext.BidderAdverxo: adverxo.Builder, openrtb_ext.BidderAdView: adview.Builder, openrtb_ext.BidderAdxcg: adxcg.Builder, openrtb_ext.BidderAdyoulike: adyoulike.Builder, @@ -359,6 +362,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderLmKiviads: lmkiviads.Builder, openrtb_ext.BidderKobler: kobler.Builder, openrtb_ext.BidderKrushmedia: krushmedia.Builder, + openrtb_ext.BidderKueezRTB: kueezrtb.Builder, openrtb_ext.BidderLemmadigital: lemmadigital.Builder, openrtb_ext.BidderVungle: vungle.Builder, openrtb_ext.BidderLimelightDigital: limelightDigital.Builder, diff --git a/go.mod b/go.mod index f5d9ee84483..dc6fad069df 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ 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-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/golang/glog v1.1.0 github.com/google/go-cmp v0.6.0 github.com/json-iterator/go v1.1.12 @@ -42,7 +41,7 @@ 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.23.0 + golang.org/x/net v0.33.0 golang.org/x/text v0.21.0 google.golang.org/grpc v1.56.3 gopkg.in/evanphx/json-patch.v4 v4.12.0 diff --git a/go.sum b/go.sum index c7977cb07ed..a98f1f7a720 100644 --- a/go.sum +++ b/go.sum @@ -164,8 +164,6 @@ github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZg github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= -github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= @@ -410,8 +408,6 @@ github.com/prebid/go-gdpr v1.12.0 h1:OrjQ7Uc+lCRYaOirQ48jjG/PBMvZsKNAaRTgzxN6iZ0 github.com/prebid/go-gdpr v1.12.0/go.mod h1:mPZAdkRxn+iuSjaUuJAi9+0SppBOdM1PCzv/55UH3pY= github.com/prebid/go-gpp v0.2.0 h1:41Ssxd4Zxr50WgwG1q/1+6awGU3pFnwV7FR4XCLQSuM= github.com/prebid/go-gpp v0.2.0/go.mod h1:b0TLoVln+HXFD9L9xeimxIH3FN8WDKPJ42auslxEkow= -github.com/prebid/openrtb/v20 v20.1.0 h1:Rb+Z3H3UxiqqnjgJK3R9Wt73ibrh7HPzG7ikBckQNqc= -github.com/prebid/openrtb/v20 v20.1.0/go.mod h1:hLBrA/APkSrxs5MaW639l+y/EAHivDfRagO2TX/wbSc= github.com/prebid/openrtb/v20 v20.3.0 h1:56z5mIrZ4FdjKxiu3Del0O4890f4AZpvz5PgPLMY1j0= github.com/prebid/openrtb/v20 v20.3.0/go.mod h1:hLBrA/APkSrxs5MaW639l+y/EAHivDfRagO2TX/wbSc= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -636,8 +632,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.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 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= diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 2069d7ee057..22df1c7da2c 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -45,6 +45,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAdtelligent, BidderAdTonos, BidderAdvangelists, + BidderAdverxo, BidderAdView, BidderAdxcg, BidderAdyoulike, @@ -141,6 +142,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderLmKiviads, BidderKobler, BidderKrushmedia, + BidderKueezRTB, BidderLemmadigital, BidderLimelightDigital, BidderLockerDome, @@ -386,6 +388,7 @@ const ( BidderAdTonos BidderName = "adtonos" BidderAdtelligent BidderName = "adtelligent" BidderAdvangelists BidderName = "advangelists" + BidderAdverxo BidderName = "adverxo" BidderAdView BidderName = "adview" BidderAdxcg BidderName = "adxcg" BidderAdyoulike BidderName = "adyoulike" @@ -482,6 +485,7 @@ const ( BidderLmKiviads BidderName = "lm_kiviads" BidderKobler BidderName = "kobler" BidderKrushmedia BidderName = "krushmedia" + BidderKueezRTB BidderName = "kueezrtb" BidderLemmadigital BidderName = "lemmadigital" BidderLimelightDigital BidderName = "limelightDigital" BidderLockerDome BidderName = "lockerdome" diff --git a/openrtb_ext/imp_adverxo.go b/openrtb_ext/imp_adverxo.go new file mode 100644 index 00000000000..6c54424f48e --- /dev/null +++ b/openrtb_ext/imp_adverxo.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtAdverxo struct { + AdUnitId int `json:"adUnitId"` + Auth string `json:"auth"` +} diff --git a/openrtb_ext/imp_kueezrtb.go b/openrtb_ext/imp_kueezrtb.go new file mode 100644 index 00000000000..79f4ae99e54 --- /dev/null +++ b/openrtb_ext/imp_kueezrtb.go @@ -0,0 +1,6 @@ +package openrtb_ext + +// ImpExtKueez defines the contract for bidrequest.imp[i].ext.prebid.bidder.kueezrtb +type ImpExtKueez struct { + ConnectionId string `json:"cId"` +} diff --git a/openrtb_ext/imp_sovrn.go b/openrtb_ext/imp_sovrn.go index 362463f9513..86d0d745428 100644 --- a/openrtb_ext/imp_sovrn.go +++ b/openrtb_ext/imp_sovrn.go @@ -1,8 +1,8 @@ package openrtb_ext type ExtImpSovrn struct { - TagId string `json:"tagId,omitempty"` - Tagid string `json:"tagid,omitempty"` - BidFloor float64 `json:"bidfloor,omitempty"` - AdUnitCode string `json:"adunitcode,omitempty"` + TagId string `json:"tagId,omitempty"` + Tagid string `json:"tagid,omitempty"` + BidFloor interface{} `json:"bidfloor,omitempty"` + AdUnitCode string `json:"adunitcode,omitempty"` } diff --git a/static/bidder-info/adport.yaml b/static/bidder-info/adport.yaml new file mode 100644 index 00000000000..b6afd1a9f6b --- /dev/null +++ b/static/bidder-info/adport.yaml @@ -0,0 +1,9 @@ +endpoint: "https://adport.pbsadverxo.com/auction?id={{.AdUnit}}&auth={{.TokenID}}" +aliasOf: "adverxo" +userSync: + iframe: + url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://adport.pbsadverxo.com/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID diff --git a/static/bidder-info/adverxo.yaml b/static/bidder-info/adverxo.yaml new file mode 100644 index 00000000000..c088490d22b --- /dev/null +++ b/static/bidder-info/adverxo.yaml @@ -0,0 +1,22 @@ +endpoint: "https://pbsadverxo.com/auction?id={{.AdUnit}}&auth={{.TokenID}}" +endpointCompression: gzip +maintainer: + email: "developer@adverxo.com" +capabilities: + app: + mediaTypes: + - banner + - native + - video + site: + mediaTypes: + - banner + - native + - video +userSync: + iframe: + url: https://pbsadverxo.com/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://pbsadverxo.com/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID diff --git a/static/bidder-info/bidsmind.yaml b/static/bidder-info/bidsmind.yaml new file mode 100644 index 00000000000..ca2ec44d66f --- /dev/null +++ b/static/bidder-info/bidsmind.yaml @@ -0,0 +1,9 @@ +endpoint: "https://bidsmind.pbsadverxo.com/auction?id={{.AdUnit}}&auth={{.TokenID}}" +aliasOf: "adverxo" +userSync: + iframe: + url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID + redirect: + url: https://bidsmind.pbsadverxo.com/usync?type=image&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: $UID diff --git a/static/bidder-info/kueezrtb.yaml b/static/bidder-info/kueezrtb.yaml new file mode 100644 index 00000000000..4242e702d7c --- /dev/null +++ b/static/bidder-info/kueezrtb.yaml @@ -0,0 +1,20 @@ +endpoint: "https://prebidsrvr.kueezrtb.com/openrtb/" +maintainer: + email: "rtb@kueez.com" +gvlVendorID: 1165 +endpointCompression: gzip +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + iframe: + url: https://sync.kueezrtb.com/api/user/html/62ce79e7dd15099534ae5e04?pbs=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}} + userMacro: ${userId} +openrtb: + gpp_supported: true \ No newline at end of file diff --git a/static/bidder-info/mobupps.yaml b/static/bidder-info/mobupps.yaml new file mode 100644 index 00000000000..bb35990b80a --- /dev/null +++ b/static/bidder-info/mobupps.yaml @@ -0,0 +1,9 @@ +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 diff --git a/static/bidder-params/adverxo.json b/static/bidder-params/adverxo.json new file mode 100644 index 00000000000..72a1b727396 --- /dev/null +++ b/static/bidder-params/adverxo.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Adverxo Adapter Params", + "description": "A schema which validates params accepted by the Adverxo adapter", + "type": "object", + "properties": { + "adUnitId": { + "type": "integer", + "minimum": 1, + "description": "Unique identifier for the ad unit in Adverxo platform." + }, + "auth": { + "type": "string", + "minLength": 6, + "description": "Authentication token provided by Adverxo platform for the AdUnit." + } + }, + "required": ["adUnitId", "auth"] + } \ No newline at end of file diff --git a/static/bidder-params/kueezrtb.json b/static/bidder-params/kueezrtb.json new file mode 100644 index 00000000000..742412f088b --- /dev/null +++ b/static/bidder-params/kueezrtb.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Kueez RTB Adapter Params", + "description": "A schema which validates params accepted by the Kueez RTB adapter", + "type": "object", + "properties": { + "cId": { + "type": "string", + "description": "The connection id.", + "minLength": 1, + "pattern": "^[a-zA-Z0-9_]+$" + } + }, + "required": [ + "cId" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/static/bidder-params/sovrn.json b/static/bidder-params/sovrn.json index d821a808f97..7f81604a9ff 100644 --- a/static/bidder-params/sovrn.json +++ b/static/bidder-params/sovrn.json @@ -14,8 +14,16 @@ "description": "An ID which identifies the sovrn ad tag (DEPRECATED, use \"tagid\" instead)" }, "bidfloor": { - "type": "number", - "description": "The minimium acceptable bid, in CPM, using US Dollars" + "anyOf": [ + { + "type": "number", + "description": "The minimum acceptable bid, in CPM, using US Dollars" + }, + { + "type": "string", + "description": "The minimum acceptable bid, in CPM, using US Dollars (as a string)" + } + ] }, "adunitcode": { "type": "string",