diff --git a/adapters/adelerate/adelerate.go b/adapters/adelerate/adelerate.go new file mode 100644 index 00000000000..f9198464eac --- /dev/null +++ b/adapters/adelerate/adelerate.go @@ -0,0 +1,138 @@ +package adelerate + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type reqBidderExt struct { + Bidder openrtb_ext.ImpExtAdelerate `json:"bidder"` +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + validImps := make([]openrtb2.Imp, 0, len(request.Imp)) + + for i := range request.Imp { + currImp := request.Imp[i] + + var bidderExt reqBidderExt + if err := jsonutil.Unmarshal(currImp.Ext, &bidderExt); err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. err: %s", i, err.Error()), + }) + continue + } + + if bidderExt.Bidder.Floor > 0 && currImp.BidFloor == 0 { + currImp.BidFloor = bidderExt.Bidder.Floor + if bidderExt.Bidder.FloorCurrency != "" { + currImp.BidFloorCur = bidderExt.Bidder.FloorCurrency + } else { + currImp.BidFloorCur = "USD" + } + } + + currImp.Secure = openrtb2.Int8Ptr(1) + + validImps = append(validImps, currImp) + } + + if len(validImps) == 0 { + return nil, errs + } + + reqCopy := *request + reqCopy.Imp = validImps + + adapterReq, err := a.buildRequest(&reqCopy) + if err != nil { + return nil, append(errs, err) + } + + return []*adapters.RequestData{adapterReq}, errs +} + +func (a *adapter) buildRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) { + reqJSON, err := jsonutil.Marshal(request) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + return &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, err := getMediaTypeForBid(seatBid.Bid[i]) + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", fmt.Errorf("unsupported MType %d for bid %s", bid.MType, bid.ID) + } +} \ No newline at end of file diff --git a/adapters/adelerate/adelerate_test.go b/adapters/adelerate/adelerate_test.go new file mode 100644 index 00000000000..d9451814c9a --- /dev/null +++ b/adapters/adelerate/adelerate_test.go @@ -0,0 +1,20 @@ +package adelerate + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdelerate, config.Adapter{ + Endpoint: "https://pbs.bidelerate.com/openrtb2/auction"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adeleratetest", bidder) +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/exemplary/banner-with-existing-bidfloor.json b/adapters/adelerate/adeleratetest/exemplary/banner-with-existing-bidfloor.json new file mode 100644 index 00000000000..a5f8a38772a --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/banner-with-existing-bidfloor.json @@ -0,0 +1,109 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "bidfloor": 3.0, + "bidfloorcur": "GBP", + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 1.5, + "floorCurrency": "EUR" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "bidfloor": 3.0, + "bidfloorcur": "GBP", + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 1.5, + "floorCurrency": "EUR" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 4.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 4.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/adelerate/adeleratetest/exemplary/banner-with-floor-default-currency.json b/adapters/adelerate/adeleratetest/exemplary/banner-with-floor-default-currency.json new file mode 100644 index 00000000000..9da9bbb8847 --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/banner-with-floor-default-currency.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 2.0 + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "bidfloor": 2.0, + "bidfloorcur": "USD", + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 2.0 + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/adelerate/adeleratetest/exemplary/banner-with-floor.json b/adapters/adelerate/adeleratetest/exemplary/banner-with-floor.json new file mode 100644 index 00000000000..62eb7bc343b --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/banner-with-floor.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 1.5, + "floorCurrency": "EUR" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "bidfloor": 1.5, + "bidfloorcur": "EUR", + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1", + "floor": 1.5, + "floorCurrency": "EUR" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 2.0, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/exemplary/multi-imp.json b/adapters/adelerate/adeleratetest/exemplary/multi-imp.json new file mode 100644 index 00000000000..da47509c922 --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/multi-imp.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "placement-1", + "publisherId": "publisher-1" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + {"w": 728, "h": 90} + ] + }, + "ext": { + "bidder": { + "placementId": "placement-2", + "publisherId": "publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "placement-1", + "publisherId": "publisher-1" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [ + {"w": 728, "h": 90} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "placement-2", + "publisherId": "publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id-1", "test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "test-imp-id-1", + "price": 1.5, + "adm": "
ad 1
", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + { + "id": "bid-2", + "impid": "test-imp-id-2", + "price": 2.0, + "adm": "
ad 2
", + "crid": "creative-2", + "w": 728, + "h": 90, + "mtype": 1 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "test-imp-id-1", + "price": 1.5, + "adm": "
ad 1
", + "crid": "creative-1", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-2", + "impid": "test-imp-id-2", + "price": 2.0, + "adm": "
ad 2
", + "crid": "creative-2", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/adelerate/adeleratetest/exemplary/simple-banner.json b/adapters/adelerate/adeleratetest/exemplary/simple-banner.json new file mode 100644 index 00000000000..e1012a5fec1 --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/simple-banner.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250}, + {"w": 728, "h": 90} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250}, + {"w": 728, "h": 90} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/exemplary/simple-native.json b/adapters/adelerate/adeleratetest/exemplary/simple-native.json new file mode 100644 index 00000000000..362bdca64b8 --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/simple-native.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}}]}", + "ver": "1.2" + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.0, + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}],\"link\":{\"url\":\"https://click.example.com\"}}", + "crid": "native-creative-101", + "mtype": 4 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 3.0, + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Title\"}}],\"link\":{\"url\":\"https://click.example.com\"}}", + "crid": "native-creative-101", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/exemplary/simple-video.json b/adapters/adelerate/adeleratetest/exemplary/simple-video.json new file mode 100644 index 00000000000..14bad1d5deb --- /dev/null +++ b/adapters/adelerate/adeleratetest/exemplary/simple-video.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [1, 2, 3], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [1, 2, 3], + "w": 640, + "h": 480 + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "https://example.com/page" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 5.0, + "adm": "", + "crid": "video-creative-789", + "w": 640, + "h": 480, + "mtype": 2 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 5.0, + "adm": "", + "crid": "video-creative-789", + "w": 640, + "h": 480, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/supplemental/bad-request.json b/adapters/adelerate/adeleratetest/supplemental/bad-request.json new file mode 100644 index 00000000000..e83d3eab466 --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/bad-request.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/adelerate/adeleratetest/supplemental/bad-server-response.json b/adapters/adelerate/adeleratetest/supplemental/bad-server-response.json new file mode 100644 index 00000000000..201856618f7 --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/bad-server-response.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "invalid json" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found .*", + "comparison": "regex" + } + ] +} diff --git a/adapters/adelerate/adeleratetest/supplemental/invalid-ext.json b/adapters/adelerate/adeleratetest/supplemental/invalid-ext.json new file mode 100644 index 00000000000..05fdd0bb48c --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/invalid-ext.json @@ -0,0 +1,27 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": "invalid" + } + } + ], + "site": { + "domain": "example.com" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Invalid imp.ext for impression index 0. err: .*", + "comparison": "regex" + } + ] +} diff --git a/adapters/adelerate/adeleratetest/supplemental/no-content.json b/adapters/adelerate/adeleratetest/supplemental/no-content.json new file mode 100644 index 00000000000..c68c047fef9 --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/no-content.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/supplemental/server-error.json b/adapters/adelerate/adeleratetest/supplemental/server-error.json new file mode 100644 index 00000000000..b569b88579e --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/server-error.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 503, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/adelerate/adeleratetest/supplemental/unknown-media-type.json b/adapters/adelerate/adeleratetest/supplemental/unknown-media-type.json new file mode 100644 index 00000000000..00c392088db --- /dev/null +++ b/adapters/adelerate/adeleratetest/supplemental/unknown-media-type.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://pbs.bidelerate.com/openrtb2/auction", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + {"w": 300, "h": 250} + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "test-placement-1", + "publisherId": "test-publisher-1" + } + } + } + ], + "site": { + "domain": "example.com" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "
test ad
", + "crid": "creative-123", + "w": 300, + "h": 250, + "mtype": 0 + } + ], + "seat": "adelerate" + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unsupported MType 0 for bid test-bid-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/adelerate/params_test.go b/adapters/adelerate/params_test.go new file mode 100644 index 00000000000..015b9fd1aee --- /dev/null +++ b/adapters/adelerate/params_test.go @@ -0,0 +1,54 @@ +package adelerate + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +var validParams = []string{ + `{"placementId":"123", "publisherId":"456"}`, + `{"placementId":"abc", "publisherId":"def", "floor": 1.5, "floorCurrency": "EUR"}`, + `{"placementId":"abc", "publisherId":"def", "floor": 0.5}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `[]`, + `{}`, + `{"placementId":"123"}`, + `{"publisherId":"456"}`, + `{"placementId":"", "publisherId":"456"}`, + `{"placementId":"123", "publisherId":""}`, + `{"some": "param"}`, +} + +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.BidderAdelerate, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected adelerate 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.BidderAdelerate, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 630fbe348b9..318f1a9bc96 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -8,6 +8,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/acuityads" "github.com/prebid/prebid-server/v4/adapters/adagio" "github.com/prebid/prebid-server/v4/adapters/adelement" + "github.com/prebid/prebid-server/v4/adapters/adelerate" "github.com/prebid/prebid-server/v4/adapters/adf" "github.com/prebid/prebid-server/v4/adapters/adgeneration" "github.com/prebid/prebid-server/v4/adapters/adhese" @@ -275,6 +276,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAcuityAds: acuityads.Builder, openrtb_ext.BidderAdagio: adagio.Builder, openrtb_ext.BidderAdelement: adelement.Builder, + openrtb_ext.BidderAdelerate: adelerate.Builder, openrtb_ext.BidderAdf: adf.Builder, openrtb_ext.BidderAdgeneration: adgeneration.Builder, openrtb_ext.BidderAdhese: adhese.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1b61ff724e2..9828ab9992e 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -24,6 +24,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAcuityAds, BidderAdagio, BidderAdelement, + BidderAdelerate, BidderAdf, BidderAdgeneration, BidderAdhese, @@ -398,6 +399,7 @@ const ( BidderAcuityAds BidderName = "acuityads" BidderAdagio BidderName = "adagio" BidderAdelement BidderName = "adelement" + BidderAdelerate BidderName = "adelerate" BidderAdf BidderName = "adf" BidderAdgeneration BidderName = "adgeneration" BidderAdhese BidderName = "adhese" diff --git a/openrtb_ext/imp_adelerate.go b/openrtb_ext/imp_adelerate.go new file mode 100644 index 00000000000..af6d06625b7 --- /dev/null +++ b/openrtb_ext/imp_adelerate.go @@ -0,0 +1,8 @@ +package openrtb_ext + +type ImpExtAdelerate struct { + PlacementId string `json:"placementId"` + PublisherId string `json:"publisherId"` + Floor float64 `json:"floor,omitempty"` + FloorCurrency string `json:"floorCurrency,omitempty"` +} \ No newline at end of file diff --git a/static/bidder-info/adelerate.yaml b/static/bidder-info/adelerate.yaml new file mode 100644 index 00000000000..bba4f0ff872 --- /dev/null +++ b/static/bidder-info/adelerate.yaml @@ -0,0 +1,21 @@ +endpoint: "https://pbs.bidelerate.com/openrtb2/auction" +maintainer: + email: "support@adelerate.com" +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + iframe: + url: "https://pbs.bidelerate.com/cookie_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" + redirect: + url: "https://pbs.bidelerate.com/cookie_sync/pixel?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}" + userMacro: "[UID]" \ No newline at end of file diff --git a/static/bidder-params/adelerate.json b/static/bidder-params/adelerate.json new file mode 100644 index 00000000000..0ae85b2baaa --- /dev/null +++ b/static/bidder-params/adelerate.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Adelerate Adapter Params", + "description": "A schema which validates params accepted by the Adelerate adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "The placement ID provided by Adelerate" + }, + "publisherId": { + "type": "string", + "minLength": 1, + "description": "The publisher ID provided by Adelerate" + }, + "floor": { + "type": "number", + "description": "Minimum CPM price. Use of Prebid Floors module is preferred." + }, + "floorCurrency": { + "type": "string", + "description": "Currency for the floor param. Defaults to USD." + } + }, + "required": [ + "placementId", + "publisherId" + ] +} \ No newline at end of file