Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
45 changes: 45 additions & 0 deletions adapters/targetVideo/params_test.go
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}`,
Comment thread
Taxel marked this conversation as resolved.
`{"placementId": ""}`,
}
139 changes: 139 additions & 0 deletions adapters/targetVideo/targetvideo.go
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) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The 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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 {
Comment thread
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
Comment thread
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
}
19 changes: 19 additions & 0 deletions adapters/targetVideo/targetvideo_test.go
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)
}
116 changes: 116 additions & 0 deletions adapters/targetVideo/targetvideotest/exemplary/app-video.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"mockBidRequest": {
"id": "test-request-id-video",
"app": {
Comment thread
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"
}]
}
]
}
Loading
Loading