-
Notifications
You must be signed in to change notification settings - Fork 902
New Adapter: targetVideo #4593
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
base: master
Are you sure you want to change the base?
New Adapter: targetVideo #4593
Changes from all commits
d48e042
197d704
85c95b5
192ff51
b5eebc5
e0eac3d
8331306
377a133
4fe67ea
5e5d533
fc2551a
a2ef146
9504036
66c82f6
92a1b1e
1a57b78
5a24a61
324f6dc
ccc67ba
3f08288
2743fbd
082d2db
8e9e7b4
13cbc01
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,45 @@ | ||
| package targetVideo | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "testing" | ||
|
|
||
| "github.com/prebid/prebid-server/v4/openrtb_ext" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestValidParams(t *testing.T) { | ||
| validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") | ||
| require.NoError(t, err, "Failed to fetch the json-schemas") | ||
|
|
||
| for _, validParam := range validParams { | ||
| assert.NoError(t, validator.Validate(openrtb_ext.BidderTargetVideo, json.RawMessage(validParam)), | ||
| "Schema rejected targetVideo params: %s", validParam) | ||
| } | ||
| } | ||
|
|
||
| func TestInvalidParams(t *testing.T) { | ||
| validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") | ||
| require.NoError(t, err, "Failed to fetch the json-schemas") | ||
|
|
||
| for _, invalidParam := range invalidParams { | ||
| assert.Error(t, validator.Validate(openrtb_ext.BidderTargetVideo, json.RawMessage(invalidParam)), | ||
| "Schema should have rejected unexpected params: %s", invalidParam) | ||
| } | ||
| } | ||
|
|
||
| var validParams = []string{ | ||
| `{"placementId":846}`, | ||
| `{"placementId":"846"}`, | ||
| } | ||
|
|
||
| var invalidParams = []string{ | ||
| `null`, | ||
| `nil`, | ||
| `undefined`, | ||
| `{"placementId": "%9"}`, | ||
| `{"publisherId": "as9""}`, | ||
| `{"placementId": true}`, | ||
| `{"placementId": ""}`, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| package targetVideo | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "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 | ||
| } | ||
|
|
||
| func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
| var errors []error | ||
| totalImps := len(request.Imp) | ||
| adapterRequests := make([]*adapters.RequestData, 0, totalImps) | ||
|
|
||
| // Split multi-imp request into multiple ad server requests. SRA is currently not recommended. | ||
| for i := 0; i < totalImps; i++ { | ||
| adapterReq, err := a.makeRequest(*request, request.Imp[i]) | ||
| if err != nil { | ||
| errors = append(errors, err) | ||
| continue | ||
| } | ||
| adapterRequests = append(adapterRequests, adapterReq) | ||
| } | ||
|
|
||
| return adapterRequests, errors | ||
| } | ||
|
|
||
| func (a *adapter) makeRequest(request openrtb2.BidRequest, imp openrtb2.Imp) (*adapters.RequestData, error) { | ||
|
Collaborator
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. You're missing error path test coverage. After you've made the suggested simplifications to this function, please add additional tests to the supplemental folder to cover each of the unmarshal error paths. You can do this by simply sending a mock bid request with the data under consideration malformed or of a mismatched type. |
||
|
|
||
| // For now, this adapter sends one imp per request, but we still | ||
| // iterate over all imps in the request to perform the required | ||
| // imp.ext transformation. | ||
| request.Imp = []openrtb2.Imp{imp} | ||
|
|
||
| for i := range request.Imp { | ||
|
|
||
| var extBidder adapters.ExtImpBidder | ||
| if err := jsonutil.Unmarshal(imp.Ext, &extBidder); err != nil { | ||
| return nil, &errortypes.BadInput{Message: "Invalid ext.bidder"} | ||
| } | ||
| var extImpTargetVideo openrtb_ext.ExtImpTargetVideo | ||
| jsonutil.Unmarshal(extBidder.Bidder, &extImpTargetVideo) | ||
|
Contributor
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. missing a error check |
||
| prebid := extBidder.Prebid | ||
| if prebid == nil { | ||
| prebid = &openrtb_ext.ExtImpPrebid{} | ||
| } | ||
| if prebid.StoredRequest == nil { | ||
|
Taxel marked this conversation as resolved.
|
||
| prebid.StoredRequest = &openrtb_ext.ExtStoredRequest{} | ||
| } | ||
| prebid.StoredRequest.ID = fmt.Sprintf("%d", extImpTargetVideo.PlacementId) | ||
|
|
||
| var extMap map[string]json.RawMessage | ||
| if err := jsonutil.Unmarshal(imp.Ext, &extMap); err != nil { | ||
| return nil, &errortypes.BadInput{Message: fmt.Sprintf("error parsing imp.ext, err: %s", err)} | ||
| } | ||
| delete(extMap, "bidder") | ||
|
|
||
| prebidRaw, err := jsonutil.Marshal(prebid) | ||
| if err != nil { | ||
| return nil, &errortypes.BadInput{Message: fmt.Sprintf("error building imp.ext.prebid, err: %s", err)} | ||
| } | ||
| extMap["prebid"] = prebidRaw | ||
|
|
||
| extRaw, err := jsonutil.Marshal(extMap) | ||
| if err != nil { | ||
| return nil, &errortypes.BadInput{Message: fmt.Sprintf("error building imp.ext, err: %s", err)} | ||
| } | ||
|
|
||
| request.Imp[i].Ext = extRaw | ||
|
Taxel marked this conversation as resolved.
|
||
|
|
||
| } | ||
|
|
||
| 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: "POST", | ||
| Uri: a.endpoint, | ||
| Body: reqJSON, | ||
| Headers: headers, | ||
| ImpIDs: openrtb_ext.GetImpIDs(request.Imp), | ||
| }, nil | ||
| } | ||
|
|
||
| func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
| if adapters.IsResponseStatusCodeNoContent(httpRes) { | ||
| return nil, nil | ||
| } | ||
| if statusError := adapters.CheckResponseStatusCodeForErrors(httpRes); statusError != nil { | ||
| return nil, []error{statusError} | ||
| } | ||
|
|
||
| bidResp, errResp := prepareBidResponse(httpRes.Body) | ||
| if errResp != nil { | ||
| return nil, []error{errResp} | ||
| } | ||
|
|
||
| br := adapters.NewBidderResponse() | ||
|
|
||
| for _, sb := range bidResp.SeatBid { | ||
| for i := range sb.Bid { | ||
| bid := sb.Bid[i] | ||
| br.Bids = append(br.Bids, &adapters.TypedBid{Bid: &bid, BidType: openrtb_ext.BidTypeVideo}) | ||
| br.Currency = bidResp.Cur | ||
| } | ||
| } | ||
| return br, nil | ||
| } | ||
|
|
||
| func prepareBidResponse(body []byte) (openrtb2.BidResponse, error) { | ||
| var response openrtb2.BidResponse | ||
| if err := jsonutil.Unmarshal(body, &response); err != nil { | ||
| return response, err | ||
| } | ||
| return response, nil | ||
| } | ||
|
|
||
| func Builder(bidderName openrtb_ext.BidderName, cfg config.Adapter, server config.Server) (adapters.Bidder, error) { | ||
| bidder := &adapter{ | ||
| endpoint: cfg.Endpoint, | ||
| } | ||
| return bidder, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package targetVideo | ||
|
|
||
| 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" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestJsonSamples(t *testing.T) { | ||
| bidder, buildErr := Builder(openrtb_ext.BidderTargetVideo, config.Adapter{ | ||
| Endpoint: "http://localhost/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) | ||
|
|
||
| require.NoError(t, buildErr, "Builder returned unexpected error") | ||
|
|
||
| adapterstest.RunJSONBidderTest(t, "targetvideotest", bidder) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| { | ||
| "mockBidRequest": { | ||
| "id": "test-request-id-video", | ||
| "app": { | ||
|
linux019 marked this conversation as resolved.
|
||
| "id": "appID", | ||
| "publisher": { | ||
| "id": "uniq_pub_id" | ||
| } | ||
| }, | ||
| "cur": ["EUR"], | ||
| "imp": [ | ||
| { | ||
| "id": "test-imp-id-video", | ||
| "video": { | ||
| "mimes": ["video/mp4"], | ||
| "w": 640, | ||
| "h": 360 | ||
| }, | ||
| "ext": { | ||
| "bidder": { | ||
| "placementId": "77777" | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "device": { | ||
| "ua": "test-user-agent" | ||
| } | ||
| }, | ||
| "httpCalls": [ | ||
| { | ||
| "expectedRequest": { | ||
| "headers": { | ||
| "Accept": ["application/json"], | ||
| "Content-Type": ["application/json;charset=utf-8"] | ||
| }, | ||
| "uri": "http://localhost/pbs", | ||
| "body": { | ||
| "id": "test-request-id-video", | ||
| "app": { | ||
| "id": "appID", | ||
| "publisher": { | ||
| "id": "uniq_pub_id" | ||
| } | ||
| }, | ||
| "imp": [ | ||
| { | ||
| "id": "test-imp-id-video", | ||
| "video": { | ||
| "mimes": ["video/mp4"], | ||
| "w": 640, | ||
| "h": 360 | ||
| }, | ||
| "ext": { | ||
| "prebid": { | ||
| "storedrequest": { | ||
| "id": "77777" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "device": { | ||
| "ua": "test-user-agent" | ||
| }, | ||
| "cur": ["EUR"] | ||
| }, | ||
| "impIDs":["test-imp-id-video"] | ||
| }, | ||
| "mockResponse": { | ||
| "status": 200, | ||
| "body": { | ||
| "id": "test-request-id-video", | ||
| "seatbid": [ | ||
| { | ||
| "seat": "targetVideo", | ||
| "bid": [ | ||
| { | ||
| "id": "randomID", | ||
| "impid": "test-imp-id-video", | ||
| "price": 5.5, | ||
| "adid": "12345678", | ||
| "adm": "test-imp-id-video", | ||
| "cid": "789", | ||
| "crid": "12345678", | ||
| "h": 360, | ||
| "w": 640 | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "cur": "EUR" | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "expectedBidResponses": [ | ||
| { | ||
| "currency": "EUR", | ||
| "bids" : [{ | ||
| "bid": { | ||
| "id": "randomID", | ||
| "adid": "12345678", | ||
| "impid": "test-imp-id-video", | ||
| "price": 5.5, | ||
| "adm": "test-imp-id-video", | ||
| "crid": "12345678", | ||
| "cid": "789", | ||
| "h": 360, | ||
| "w": 640 | ||
| }, | ||
| "type": "video" | ||
| }] | ||
| } | ||
| ] | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.