-
Notifications
You must be signed in to change notification settings - Fork 812
New adapter: Adagio #1907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New adapter: Adagio #1907
Changes from 4 commits
626cf32
7e16e06
6cd91e1
426bc23
473d9a6
3533b2a
81bbdb3
9194225
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package adagio | ||
|
||
import ( | ||
"bytes" | ||
"compress/gzip" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/mxmCherry/openrtb/v15/openrtb2" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/config" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
"net/http" | ||
) | ||
|
||
// Builder builds a new instance of the Adagio adapter for the given bidder with the given config. | ||
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { | ||
bidder := &adapter{ | ||
endpoint: config.Endpoint, | ||
} | ||
return bidder, nil | ||
} | ||
|
||
type adapter struct { | ||
endpoint string | ||
} | ||
|
||
type extBid struct { | ||
Prebid *openrtb_ext.ExtBidPrebid | ||
} | ||
|
||
// MakeRequests prepares the HTTP requests which should be made to fetch bids. | ||
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
json, err := json.Marshal(request) | ||
if err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
headers.Add("Accept", "application/json") | ||
|
||
if request.Device != nil { | ||
if len(request.Device.IPv6) > 0 { | ||
headers.Add("X-Forwarded-For", request.Device.IPv6) | ||
} | ||
if len(request.Device.IP) > 0 { | ||
headers.Add("X-Forwarded-For", request.Device.IP) | ||
} | ||
} | ||
|
||
if request.Test == 0 { | ||
// Gzip the body | ||
// Note: Gzipping could be handled natively later: https://github.com/prebid/prebid-server/issues/1812 | ||
var bodyBuf bytes.Buffer | ||
gz := gzip.NewWriter(&bodyBuf) | ||
_, err = gz.Write(json) | ||
if err == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: You can make the error checking inline:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I updated |
||
err = gz.Close() | ||
if err == nil { | ||
json = bodyBuf.Bytes() | ||
headers.Add("Content-Encoding", "gzip") | ||
// /!\ Go already sets the `Accept-Encoding: gzip` header. Never add it manually, or Go won't decompress the response. | ||
//headers.Add("Accept-Encoding", "gzip") | ||
} | ||
} | ||
} | ||
|
||
requestToBidder := &adapters.RequestData{ | ||
Method: "POST", | ||
Uri: a.endpoint, | ||
Body: json, | ||
Headers: headers, | ||
} | ||
|
||
return []*adapters.RequestData{requestToBidder}, nil | ||
} | ||
|
||
const unexpectedStatusCodeFormat = "Unexpected status code: %d. Run with request.debug = 1 for more info" | ||
|
||
// MakeBids unpacks the server's response into Bids. | ||
func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, _ *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
switch response.StatusCode { | ||
case http.StatusOK: | ||
break | ||
case http.StatusNoContent: | ||
return nil, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please consider adding JSON tests for status codes other than |
||
case http.StatusServiceUnavailable: | ||
fallthrough | ||
case http.StatusBadRequest: | ||
fallthrough | ||
case http.StatusUnauthorized: | ||
fallthrough | ||
case http.StatusForbidden: | ||
err := &errortypes.BadInput{ | ||
Message: fmt.Sprintf(unexpectedStatusCodeFormat, response.StatusCode), | ||
} | ||
return nil, []error{err} | ||
default: | ||
err := &errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf(unexpectedStatusCodeFormat, response.StatusCode), | ||
} | ||
return nil, []error{err} | ||
} | ||
|
||
var openRTBBidderResponse openrtb2.BidResponse | ||
if err := json.Unmarshal(response.Body, &openRTBBidderResponse); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
bidsCapacity := len(internalRequest.Imp) | ||
errs := make([]error, 0, bidsCapacity) | ||
bidderResponse := adapters.NewBidderResponseWithBidsCapacity(bidsCapacity) | ||
var typedBid *adapters.TypedBid | ||
for _, seatBid := range openRTBBidderResponse.SeatBid { | ||
for _, bid := range seatBid.Bid { | ||
activeBid := bid | ||
|
||
activeExt := &extBid{} | ||
if err := json.Unmarshal(activeBid.Ext, activeExt); err != nil { | ||
errs = append(errs, err) | ||
} | ||
|
||
var bidType openrtb_ext.BidType | ||
if activeExt.Prebid != nil && activeExt.Prebid.Type != "" { | ||
bidType = activeExt.Prebid.Type | ||
} else { | ||
err := &errortypes.BadInput{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error code in this case should be |
||
Message: fmt.Sprintf("Failed to find native/banner/video mediaType \"%s\" ", activeBid.ImpID), | ||
} | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
typedBid = &adapters.TypedBid{Bid: &activeBid, BidType: bidType} | ||
bidderResponse.Bids = append(bidderResponse.Bids, typedBid) | ||
} | ||
} | ||
|
||
return bidderResponse, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package adagio | ||
|
||
import ( | ||
"encoding/json" | ||
"github.com/mxmCherry/openrtb/v15/openrtb2" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
"github.com/prebid/prebid-server/config" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
func buildFakeBidRequest() openrtb2.BidRequest { | ||
imp1 := openrtb2.Imp{ | ||
ID: "some-impression-id", | ||
Banner: &openrtb2.Banner{}, | ||
Ext: json.RawMessage(`{"bidder": {"organizationId": "1000", "site": "site-name", "placement": "ban_atf"}}`), | ||
} | ||
|
||
fakeBidRequest := openrtb2.BidRequest{ | ||
ID: "some-request-id", | ||
Imp: []openrtb2.Imp{imp1}, | ||
} | ||
|
||
return fakeBidRequest | ||
} | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{ | ||
Endpoint: "http://localhost/prebid_server"}) | ||
|
||
if buildErr != nil { | ||
t.Fatalf("Builder returned unexpected error %v", buildErr) | ||
} | ||
|
||
adapterstest.RunJSONBidderTest(t, "adagiotest", bidder) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may not be a bad idea to have a multiformat test. And a test or two to exercise that bad response paths in MakeBids(). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hi @hhhjort, thanks for your review. I added some tests. Let me know if it is ok you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason you hardcoded some tests in by hand rather than adding more JSON tests? |
||
} | ||
|
||
func TestMakeRequests_NoGzip(t *testing.T) { | ||
fakeBidRequest := buildFakeBidRequest() | ||
fakeBidRequest.Test = 1 // Do not use Gzip in Test Mode. | ||
|
||
bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{ | ||
Endpoint: "http://localhost/prebid_server"}) | ||
|
||
if buildErr != nil { | ||
t.Fatalf("Builder returned unexpected error %v", buildErr) | ||
} | ||
|
||
requestData, err := bidder.MakeRequests(&fakeBidRequest, nil) | ||
|
||
assert.Nil(t, err) | ||
assert.Equal(t, 1, len(requestData)) | ||
|
||
body := &openrtb2.BidRequest{} | ||
_ = json.Unmarshal(requestData[0].Body, body) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the likelihood of an |
||
|
||
assert.Equal(t, 1, len(body.Imp)) | ||
} | ||
|
||
func TestMakeRequests_Gzip(t *testing.T) { | ||
fakeBidRequest := buildFakeBidRequest() | ||
|
||
bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{ | ||
Endpoint: "http://localhost/prebid_server"}) | ||
|
||
if buildErr != nil { | ||
t.Fatalf("Builder returned unexpected error %v", buildErr) | ||
} | ||
|
||
requestData, _ := bidder.MakeRequests(&fakeBidRequest, nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please consider adding a |
||
assert.Equal(t, []string([]string{"gzip"}), requestData[0].Headers["Content-Encoding"]) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
{ | ||
"mockBidRequest": { | ||
"test": 1, | ||
"id": "some-request-id", | ||
"device": { | ||
"ua": "test-user-agent", | ||
"ip": "123.123.123.123", | ||
"language": "en", | ||
"dnt": 0 | ||
}, | ||
"tmax": 1000, | ||
"user": { | ||
"buyeruid": "awesome-user" | ||
}, | ||
"site": { | ||
"page": "test.com", | ||
"publisher": { | ||
"id": "123456789" | ||
} | ||
}, | ||
"imp": [ | ||
{ | ||
"id": "some-impression-id", | ||
"banner": { | ||
"w":320, | ||
"h":50 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"organizationId": "1000", | ||
"site": "site-name", | ||
"placement": "ban_atf" | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
"httpCalls": [ | ||
{ | ||
"expectedRequest": { | ||
"headers": { | ||
"Content-Type": [ | ||
"application/json;charset=utf-8" | ||
], | ||
"Accept": [ | ||
"application/json" | ||
], | ||
"X-Forwarded-For": [ | ||
"123.123.123.123" | ||
] | ||
}, | ||
"uri": "http://localhost/prebid_server", | ||
"body": { | ||
"test": 1, | ||
"id": "some-request-id", | ||
"device": { | ||
"ua": "test-user-agent", | ||
"ip": "123.123.123.123", | ||
"language": "en", | ||
"dnt": 0 | ||
}, | ||
"imp": [ | ||
{ | ||
"id": "some-impression-id", | ||
"banner": { | ||
"w":320, | ||
"h":50 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"organizationId": "1000", | ||
"site": "site-name", | ||
"placement": "ban_atf" | ||
} | ||
} | ||
} | ||
], | ||
"site": { | ||
"page": "test.com", | ||
"publisher": { | ||
"id": "123456789" | ||
} | ||
}, | ||
"user": { | ||
"buyeruid": "awesome-user" | ||
}, | ||
"tmax": 1000 | ||
} | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"id": "awesome-resp-id", | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"id": "a3ae1b4e2fc24a4fb45540082e98e161", | ||
"impid": "some-impression-id", | ||
"price": 3.5, | ||
"adm": "awesome-markup", | ||
"adomain": [ | ||
"awesome.com" | ||
], | ||
"crid": "20", | ||
"w": 320, | ||
"h": 50, | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
} | ||
], | ||
"seat": "adagio" | ||
} | ||
], | ||
"cur": "USD", | ||
"ext": { | ||
"responsetimemillis": { | ||
"adagio": 154 | ||
}, | ||
"tmaxrequest": 1000 | ||
} | ||
} | ||
} | ||
} | ||
], | ||
"expectedBidResponses": [ | ||
{ | ||
"bids":[ | ||
{ | ||
"bid": { | ||
"id": "a3ae1b4e2fc24a4fb45540082e98e161", | ||
"impid": "some-impression-id", | ||
"price": 3.5, | ||
"adm": "awesome-markup", | ||
"crid": "20", | ||
"adomain": [ | ||
"awesome.com" | ||
], | ||
"w": 320, | ||
"h": 50, | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
}, | ||
"type": "banner" | ||
} | ||
] | ||
} | ||
] | ||
} |
Uh oh!
There was an error while loading. Please reload this page.