Skip to content
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

Colossus bid adapter #1472

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions adapters/colossus/colossus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package colossus

import (
"encoding/json"
"fmt"
"net/http"

"github.com/buger/jsonparser"
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/openrtb_ext"
)

type ColossusAdapter struct {
URI string
}

// NewColossusBidder Initializes the Bidder
func NewColossusBidder(endpoint string) *ColossusAdapter {
return &ColossusAdapter{
URI: endpoint,
}
}

// MakeRequests create bid request for colossus demand
func (a *ColossusAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var errs []error
var err error
var tagID string

var adapterRequests []*adapters.RequestData

reqCopy := *request
for _, imp := range request.Imp {
reqCopy.Imp = []openrtb.Imp{imp}

tagID, err = jsonparser.GetString(reqCopy.Imp[0].Ext, "bidder", "TagID")
if err != nil {
errs = append(errs, err)
continue
}

reqCopy.Imp[0].TagID = tagID

adapterReq, errors := a.makeRequest(&reqCopy)
if adapterReq != nil {
adapterRequests = append(adapterRequests, adapterReq)
}
errs = append(errs, errors...)
}
return adapterRequests, errs
}

func (a *ColossusAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) {

var errs []error

reqJSON, err := json.Marshal(request)

if err != nil {
errs = append(errs, err)
return nil, errs
}

headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")
return &adapters.RequestData{
Method: "POST",
Uri: a.URI,
Body: reqJSON,
Headers: headers,
}, errs
}

// MakeBids makes the bids
func (a *ColossusAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
var errs []error

if response.StatusCode == http.StatusNoContent {
return nil, nil
}

if response.StatusCode == http.StatusNotFound {
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
}}
}

if response.StatusCode != http.StatusOK {
return nil, []error{&errortypes.BadServerResponse{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice test coverage. This looks to be the only excluded branch. Could you please add a test here to round out the lot?

Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
}}
}

var bidResp openrtb.BidResponse

if err := json.Unmarshal(response.Body, &bidResp); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)

for _, sb := range bidResp.SeatBid {
for i := range sb.Bid {
bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp)
if err != nil {
errs = append(errs, err)
} else {
b := &adapters.TypedBid{
Bid: &sb.Bid[i],
BidType: bidType,
}
bidResponse.Bids = append(bidResponse.Bids, b)
}
}
}
return bidResponse, errs
}

func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) {
mediaType := openrtb_ext.BidTypeBanner
for _, imp := range imps {
if imp.ID == impID {
if imp.Banner == nil && imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
}
return mediaType, nil
}
}

// This shouldnt happen. Lets handle it just incase by returning an error.
return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
}
}
12 changes: 12 additions & 0 deletions adapters/colossus/colossus_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package colossus

import (
"testing"

"github.com/prebid/prebid-server/adapters/adapterstest"
)

func TestJsonSamples(t *testing.T) {
colossusAdapter := NewColossusBidder("http://example.com/?c=o&m=rtb")
adapterstest.RunJSONBidderTest(t, "colossustest", colossusAdapter)
}
134 changes: 134 additions & 0 deletions adapters/colossus/colossustest/exemplary/simple-banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{
"mockBidRequest": {
"id": "test-request-id",
"imp": [
{
"id": "test-imp-id",
"banner": {
"format": [
{
"w": 300,
"h": 250
},
{
"w": 300,
"h": 600
}
]
},
"tagid": "61317",
"ext": {
"bidder": {
"TagID": "61317"
}
}
}
],
"app": {
"id": "1",
"bundle": "com.wls.testwlsapplication"
},
"device": {
"ip": "123.123.123.123",
"ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
}
},

"httpCalls": [
{
"expectedRequest": {
"uri": "http://example.com/?c=o&m=rtb",
"body": {
"id": "test-request-id",
"imp": [
{
"id": "test-imp-id",
"banner": {
"format": [
{
"w": 300,
"h": 250
},
{
"w": 300,
"h": 600
}
]
},
"tagid": "61317",
"ext": {
"bidder": {
"TagID": "61317"
}
}
}
],
"app": {
"id": "1",
"bundle": "com.wls.testwlsapplication"
},
"device": {
"ip": "123.123.123.123",
"ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
}
}
},
"mockResponse": {
"status": 200,
"body": {
"id": "test-request-id",
"seatbid": [
{
"bid": [
{
"id": "test_bid_id",
"impid": "test-imp-id",
"price": 0.27543,
"adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://colossusssp.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
"cid": "test_cid",
"crid": "test_crid",
"dealid": "test_dealid",
"w": 300,
"h": 250,
"ext": {
"prebid": {
"type": "banner"
}
}
}
],
"seat": "colossus"
}
],
"cur": "USD"
}
}
}
],

"expectedBidResponses": [
{
"bids":[
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SyntaxNode should this also have the top-level key"currency": "USD",? It looks like the JSON test infrastructure does not verify that bid response field.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The adapters.NewBidderResponseWithBidsCapacity(1) will fill the currency field with USD. If there is any chance of bidding in some other currency, you should add some code to overwrite it. Would also be nice to test bidding in other currencies if that is a thing.

{
"bid": {
"id": "test_bid_id",
"impid": "test-imp-id",
"price": 0.27543,
"adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://colossusssp.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
"cid": "test_cid",
"crid": "test_crid",
"dealid": "test_dealid",
"w": 300,
"h": 250,
"ext": {
"prebid": {
"type": "banner"
}
}
},
"type": "banner"
}
]
}
]
}
Loading