-
Notifications
You must be signed in to change notification settings - Fork 764
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
[synacormedia] Add synacormedia adapter #1029
Changes from all commits
e17042b
36bd18f
0ce2f35
e5eae19
b26ddff
35d1060
37ecb9d
ceffd22
ed8508c
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,48 @@ | ||
package synacormedia | ||
|
||
import ( | ||
"encoding/json" | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
// This file actually intends to test static/bidder-params/synacormedia.json | ||
// | ||
// These also validate the format of the external API: request.imp[i].ext.synacormedia | ||
|
||
// TestValidParams makes sure that the synacormedia schema accepts all imp.ext fields which we intend to support. | ||
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.BidderSynacormedia, json.RawMessage(validParam)); err != nil { | ||
t.Errorf("Schema rejected synacormedia params: %s", validParam) | ||
} | ||
} | ||
} | ||
|
||
// TestInvalidParams makes sure that the synacormedia schema rejects all the imp.ext fields we don't support. | ||
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.BidderSynacormedia, json.RawMessage(invalidParam)); err == nil { | ||
t.Errorf("Schema allowed unexpected params: %s", invalidParam) | ||
} | ||
} | ||
} | ||
|
||
var validParams = []string{ | ||
`{"seatId": "123"}`, | ||
} | ||
|
||
var invalidParams = []string{ | ||
`{"seatId": 123}`, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package synacormedia | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"text/template" | ||
|
||
"github.com/golang/glog" | ||
"github.com/mxmCherry/openrtb" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/macros" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
type SynacorMediaAdapter struct { | ||
EndpointTemplate template.Template | ||
} | ||
|
||
type SyncEndpointTemplateParams struct { | ||
SeatId string | ||
} | ||
|
||
type ReqExt struct { | ||
SeatId string `json:"seatId"` | ||
} | ||
|
||
func NewSynacorMediaBidder(endpointTemplate string) adapters.Bidder { | ||
syncTemplate, err := template.New("endpointTemplate").Parse(endpointTemplate) | ||
if err != nil { | ||
glog.Fatal("Unable to parse endpoint url template") | ||
return nil | ||
} | ||
return &SynacorMediaAdapter{EndpointTemplate: *syncTemplate} | ||
} | ||
|
||
func (a *SynacorMediaAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
var errs []error | ||
var bidRequests []*adapters.RequestData | ||
|
||
adapterReq, errors := a.makeRequest(request) | ||
if adapterReq != nil { | ||
bidRequests = append(bidRequests, adapterReq) | ||
} | ||
errs = append(errs, errors...) | ||
|
||
return bidRequests, errs | ||
} | ||
|
||
func (a *SynacorMediaAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) { | ||
var errs []error | ||
var validImps []openrtb.Imp | ||
var re *ReqExt | ||
var firstExtImp *openrtb_ext.ExtImpSynacormedia = nil | ||
|
||
for _, imp := range request.Imp { | ||
validImp, err := getExtImpObj(&imp) | ||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
validImps = append(validImps, imp) | ||
if firstExtImp == nil { | ||
firstExtImp = validImp | ||
} | ||
} | ||
|
||
if len(validImps) == 0 { | ||
return nil, errs | ||
} | ||
|
||
var err error | ||
|
||
if firstExtImp == nil || firstExtImp.SeatId == "" { | ||
return nil, append(errs, &errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Impression missing seat id"), | ||
}) | ||
} | ||
re = &ReqExt{SeatId: firstExtImp.SeatId} | ||
|
||
// create JSON Request Body | ||
request.Imp = validImps | ||
request.Ext, err = json.Marshal(re) | ||
if err != nil { | ||
return nil, append(errs, err) | ||
} | ||
|
||
reqJSON, err := json.Marshal(request) | ||
if err != nil { | ||
return nil, append(errs, err) | ||
} | ||
|
||
// set Request Headers | ||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
guscarreon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
headers.Add("Accept", "application/json") | ||
|
||
// create Request Uri | ||
reqUri, err := a.buildEndpointURL(firstExtImp) | ||
if err != nil { | ||
return nil, append(errs, err) | ||
} | ||
|
||
return &adapters.RequestData{ | ||
Method: http.MethodPost, | ||
Uri: reqUri, | ||
Body: reqJSON, | ||
Headers: headers, | ||
}, errs | ||
} | ||
|
||
// Builds enpoint url based on adapter-specific pub settings from imp.ext | ||
func (adapter *SynacorMediaAdapter) buildEndpointURL(params *openrtb_ext.ExtImpSynacormedia) (string, error) { | ||
return macros.ResolveMacros(adapter.EndpointTemplate, macros.EndpointTemplateParams{Host: params.SeatId}) | ||
} | ||
|
||
func getExtImpObj(imp *openrtb.Imp) (*openrtb_ext.ExtImpSynacormedia, error) { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: err.Error(), | ||
} | ||
} | ||
|
||
var synacormediaExt openrtb_ext.ExtImpSynacormedia | ||
if err := json.Unmarshal(bidderExt.Bidder, &synacormediaExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: err.Error(), | ||
} | ||
} | ||
|
||
return &synacormediaExt, nil | ||
} | ||
|
||
// MakeBids make the bids for the bid response. | ||
func (a *SynacorMediaAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
const errorMessage string = "Unexpected status code: %d. Run with request.debug = 1 for more info" | ||
switch { | ||
case response.StatusCode == http.StatusNoContent: | ||
return nil, nil | ||
case response.StatusCode == http.StatusBadRequest: | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: fmt.Sprintf(errorMessage, response.StatusCode), | ||
}} | ||
case response.StatusCode != http.StatusOK: | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf(errorMessage, 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 { | ||
var mediaType = getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) | ||
if mediaType != openrtb_ext.BidTypeBanner && mediaType != openrtb_ext.BidTypeVideo { | ||
continue | ||
} | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &sb.Bid[i], | ||
BidType: mediaType, | ||
}) | ||
} | ||
} | ||
return bidResponse, nil | ||
} | ||
|
||
func getMediaTypeForImp(impId string, imps []openrtb.Imp) openrtb_ext.BidType { | ||
mediaType := openrtb_ext.BidTypeBanner | ||
for _, imp := range imps { | ||
if imp.ID == impId { | ||
if imp.Banner != nil { | ||
break | ||
} | ||
if imp.Video != nil { | ||
mediaType = openrtb_ext.BidTypeVideo | ||
break | ||
} | ||
if imp.Native != nil { | ||
mediaType = openrtb_ext.BidTypeNative | ||
break | ||
} | ||
if imp.Audio != nil { | ||
mediaType = openrtb_ext.BidTypeAudio | ||
break | ||
} | ||
} | ||
} | ||
return mediaType | ||
} | ||
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. Function
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. Added filter. // filter out non banner and non video imps
var validRequestImps []openrtb.Imp
for _, imp := range internalRequest.Imp {
if imp.Banner != nil || imp.Video != nil {
validRequestImps = append(validRequestImps, imp)
}
} 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 don't think this for loop is exactly filtering out non banner and non video imps because if
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package synacormedia | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
adapterstest.RunJSONBidderTest(t, "synacormediatest", NewSynacorMediaBidder("http://{{.Host}}.technoratimedia.com/openrtb/bids/{{.Host}}")) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
{ | ||
"mockBidRequest": { | ||
"id": "test-request-id", | ||
"imp": [ | ||
{ | ||
"id": "test-imp-id", | ||
"banner": { | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
} | ||
] | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"seatId": "1927" | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
|
||
"httpCalls": [ | ||
{ | ||
"expectedRequest": { | ||
"uri": "http://1927.technoratimedia.com/openrtb/bids/1927", | ||
"body": { | ||
"id": "test-request-id", | ||
"ext": { | ||
"seatId": "1927" | ||
}, | ||
"imp": [ | ||
{ | ||
"id":"test-imp-id", | ||
"banner": { | ||
"format": [ | ||
{"w":300,"h":250} | ||
] | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"seatId": "1927" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"id": "1", | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"id": "test-request-id", | ||
"impid": "test-imp-id", | ||
"price": 2.69, | ||
"adomain": [ | ||
"psacentral.org" | ||
], | ||
"cid": "mock-crid", | ||
"crid": "mock-cid", | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
} | ||
], | ||
"seat": "synacormedia" | ||
} | ||
], | ||
"ext": { | ||
"responsetimemillis": { | ||
"synacormedia": 339 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
], | ||
"expectedBidResponses": [ | ||
{ | ||
"currency": "USD", | ||
"bids": [ | ||
{ | ||
"bid": { | ||
"adomain": [ | ||
"psacentral.org" | ||
], | ||
"cid": "mock-crid", | ||
"crid": "mock-cid", | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
}, | ||
"id": "test-request-id", | ||
"impid": "test-imp-id", | ||
"price": 2.69 | ||
}, | ||
"type": "banner" | ||
} | ||
] | ||
} | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does
getExtImp(&imp)
get executed twice in a row?