diff --git a/adapters/videoheroes/params_test.go b/adapters/videoheroes/params_test.go new file mode 100644 index 00000000000..d79f83245a4 --- /dev/null +++ b/adapters/videoheroes/params_test.go @@ -0,0 +1,51 @@ +package videoheroes + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +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.BidderVideoHeroes, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected VideoHeroes params: %s", validParam) + } + } +} + +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.BidderVideoHeroes, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{ "placementId": "f897beb0daba0253d8e59a098eef9311" }`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, + `{ "placementid": "f897beb0daba0253d8e59a098eef9311" }`, + `{ "PlacementId": "f897beb0daba0253d8e59a098eef9311" }`, +} diff --git a/adapters/videoheroes/videoheroes.go b/adapters/videoheroes/videoheroes.go new file mode 100755 index 00000000000..4d04cd4f8f0 --- /dev/null +++ b/adapters/videoheroes/videoheroes.go @@ -0,0 +1,157 @@ +package videoheroes + +import ( + "encoding/json" + "fmt" + "net/http" + "text/template" + + "github.com/prebid/openrtb/v17/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/macros" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type adapter struct { + endpoint *template.Template +} + +// Builder builds a new instance of the VideoHeroes adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + uri, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &adapter{ + endpoint: uri, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var videoHeroesExt *openrtb_ext.ExtImpVideoHeroes + var err error + + videoHeroesExt, err = a.getImpressionExt(&request.Imp[0]) + if err != nil { + return nil, []error{err} + } + + request.Imp[0].Ext = nil + + reqJSON, 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") + + url, err := a.buildEndpointURL(videoHeroesExt) + if err != nil { + return nil, []error{err} + } + + return []*adapters.RequestData{{ + Method: http.MethodPost, + Body: reqJSON, + Uri: url, + Headers: headers, + }}, nil +} + +func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpVideoHeroes, error) { + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + var videoHeroesExt openrtb_ext.ExtImpVideoHeroes + if err := json.Unmarshal(bidderExt.Bidder, &videoHeroesExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "ext.bidder not provided", + } + } + return &videoHeroesExt, nil +} + +func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpVideoHeroes) (string, error) { + endpointParams := macros.EndpointTemplateParams{PublisherID: params.PlacementID} + return macros.ResolveMacros(a.endpoint, endpointParams) +} + +func (a *adapter) MakeBids( + receivedRequest *openrtb2.BidRequest, + bidderRequest *adapters.RequestData, + bidderResponse *adapters.ResponseData, +) ( + *adapters.BidderResponse, + []error, +) { + + if bidderResponse.StatusCode == http.StatusNoContent { + return nil, []error{&errortypes.BadInput{Message: "No bid"}} + } + + if bidderResponse.StatusCode == http.StatusBadRequest { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", bidderResponse.StatusCode), + }} + } + + if bidderResponse.StatusCode == http.StatusServiceUnavailable { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Service Unavailable. Status Code: [ %d ] ", bidderResponse.StatusCode), + }} + } + + if bidderResponse.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", bidderResponse.StatusCode), + }} + } + + var bidResponse openrtb2.BidResponse + if err := json.Unmarshal(bidderResponse.Body, &bidResponse); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + if len(bidResponse.SeatBid) == 0 { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Empty SeatBid array", + }} + } + + bidResponseFinal := adapters.NewBidderResponseWithBidsCapacity(len(bidResponse.SeatBid[0].Bid)) + sb := bidResponse.SeatBid[0] + + for _, bid := range sb.Bid { + bidResponseFinal.Bids = append(bidResponseFinal.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: getMediaTypeForImp(bid.ImpID, receivedRequest.Imp), + }) + } + return bidResponseFinal, nil +} + +func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { + mediaType := openrtb_ext.BidTypeBanner + for _, imp := range imps { + if imp.ID == impId { + if imp.Video != nil { + mediaType = openrtb_ext.BidTypeVideo + } else if imp.Native != nil { + mediaType = openrtb_ext.BidTypeNative + } + return mediaType + } + } + return mediaType +} diff --git a/adapters/videoheroes/videoheroes_test.go b/adapters/videoheroes/videoheroes_test.go new file mode 100644 index 00000000000..ac60d56e175 --- /dev/null +++ b/adapters/videoheroes/videoheroes_test.go @@ -0,0 +1,30 @@ +package videoheroes + +import ( + "testing" + + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderVideoHeroes, config.Adapter{ + Endpoint: "http://point.contextualadv.com/?t=3&partner={{.PublisherID}}"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "videoheroestest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderVideoHeroes, config.Adapter{ + Endpoint: "{{Malformed}}"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/videoheroes/videoheroestest/exemplary/banner-app.json b/adapters/videoheroes/videoheroestest/exemplary/banner-app.json new file mode 100644 index 00000000000..17d3add92f4 --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/banner-app.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w":320, + "h":50 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w":320, + "h":50 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w":320, + "h":50 + } + ], + "type": "banner", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w":320, + "h":50 + }, + "type": "banner" + }] + } + ] + } diff --git a/adapters/videoheroes/videoheroestest/exemplary/banner-web.json b/adapters/videoheroes/videoheroestest/exemplary/banner-web.json new file mode 100644 index 00000000000..f838716340c --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/banner-web.json @@ -0,0 +1,138 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w":320, + "h":50 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w":320, + "h":50 + }, + "tagid": "tid" + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w":320, + "h":50 + } + ], + "type": "banner", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w":320, + "h":50 + }, + "type": "banner" + }] + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/exemplary/native-app.json b/adapters/videoheroes/videoheroestest/exemplary/native-app.json new file mode 100644 index 00000000000..cce8010940f --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/native-app.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100" + } + ], + "type": "native", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100" + }, + "type": "native" + }] + } + ] + } diff --git a/adapters/videoheroes/videoheroestest/exemplary/native-web.json b/adapters/videoheroes/videoheroestest/exemplary/native-web.json new file mode 100644 index 00000000000..381bac5ce82 --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/native-web.json @@ -0,0 +1,135 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "native": { + "ver":"1.1", + "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}" + }, + "tagid": "tid" + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100" + } + ], + "type": "native", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100" + }, + "type": "native" + }] + } + ] + } diff --git a/adapters/videoheroes/videoheroestest/exemplary/video-app.json b/adapters/videoheroes/videoheroestest/exemplary/video-app.json new file mode 100644 index 00000000000..96dd555d585 --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/video-app.json @@ -0,0 +1,150 @@ +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720 + } + ], + "type": "video", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720 + }, + "type": "video" + }] + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/exemplary/video-web.json b/adapters/videoheroes/videoheroestest/exemplary/video-web.json new file mode 100644 index 00000000000..243349a96b5 --- /dev/null +++ b/adapters/videoheroes/videoheroestest/exemplary/video-web.json @@ -0,0 +1,148 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720 + } + ], + "type": "video", + "seat": "videoheroes" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "123456789", + "impid": "impression-id", + "price": 2, + "adm": "adm code", + "adomain": [ + "testdomain.com" + ], + "crid": "100", + "w": 1280, + "h": 720 + }, + "type": "video" + }] + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/empty-seatbid-array.json b/adapters/videoheroes/videoheroestest/supplemental/empty-seatbid-array.json new file mode 100644 index 00000000000..3743daeaa3f --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/empty-seatbid-array.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "request-id", + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "site": { + "page": "test.com/page", + "domain": "test.com", + "cat": [ + "IAB9-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-id", + "seatbid": [ + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "videoheroes": 120 + }, + "tmaxrequest": 1000 + } + } + } + } + ], + "mockResponse": { + "status": 200, + "body": "invalid response" + }, + "expectedMakeBidsErrors": [ + { + "value": "Empty SeatBid array", + "comparison": "literal" + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/invalid-brave-ext-object.json b/adapters/videoheroes/videoheroestest/supplemental/invalid-brave-ext-object.json new file mode 100644 index 00000000000..899834e668f --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/invalid-brave-ext-object.json @@ -0,0 +1,29 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "ext.bidder not provided", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "request-id", + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": "invalid data" + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/invalid-response.json b/adapters/videoheroes/videoheroestest/supplemental/invalid-response.json new file mode 100644 index 00000000000..ad9a32c0bbe --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/invalid-response.json @@ -0,0 +1,98 @@ + +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "banner": { + "w":320, + "h":50 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "banner": { + "w":320, + "h":50 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": "invalid response" + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/status-code-bad-request.json b/adapters/videoheroes/videoheroestest/supplemental/status-code-bad-request.json new file mode 100644 index 00000000000..432540e399c --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/status-code-bad-request.json @@ -0,0 +1,108 @@ + +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 400 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/status-code-no-content.json b/adapters/videoheroes/videoheroestest/supplemental/status-code-no-content.json new file mode 100644 index 00000000000..bec17d52e8c --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/status-code-no-content.json @@ -0,0 +1,108 @@ + +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 204 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "No bid", + "comparison": "literal" + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/status-code-other-error.json b/adapters/videoheroes/videoheroestest/supplemental/status-code-other-error.json new file mode 100644 index 00000000000..cb37a4d93f8 --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/status-code-other-error.json @@ -0,0 +1,108 @@ + +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 306 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Something went wrong, please contact your Account Manager. Status Code: [ 306 ] ", + "comparison": "literal" + } + ] +} diff --git a/adapters/videoheroes/videoheroestest/supplemental/status-code-service-unavailable.json b/adapters/videoheroes/videoheroestest/supplemental/status-code-service-unavailable.json new file mode 100644 index 00000000000..38d14f4faaa --- /dev/null +++ b/adapters/videoheroes/videoheroestest/supplemental/status-code-service-unavailable.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "request-id", + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "tmax": 1000, + "user": { + "id": "some-user" + }, + "imp": [ + { + "id": "impression-id", + "tagid": "tid", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 30, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "f897beb0daba0253d8e59a098eef9311" + } + } + } + ] + }, + + "httpCalls": [{ + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ] + }, + "uri": "http://point.contextualadv.com/?t=3&partner=f897beb0daba0253d8e59a098eef9311", + "body": { + "id": "request-id", + "device": { + "ua": "useragent", + "ip": "100.100.100.100", + "language": "en" + }, + "imp": [ + { + "id": "impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 30, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "tid" + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB9-1" + ], + "bundle": "com.app.test", + "name": "Test App", + "id": "12345678" + }, + "user": { + "id": "some-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 503 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Service Unavailable. Status Code: [ 503 ] ", + "comparison": "literal" + } + ] +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 5ceaae1cdb8..71c8e987527 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -145,6 +145,7 @@ import ( "github.com/prebid/prebid-server/adapters/unicorn" "github.com/prebid/prebid-server/adapters/unruly" "github.com/prebid/prebid-server/adapters/videobyte" + "github.com/prebid/prebid-server/adapters/videoheroes" "github.com/prebid/prebid-server/adapters/vidoomy" "github.com/prebid/prebid-server/adapters/visx" "github.com/prebid/prebid-server/adapters/vrtcal" @@ -317,6 +318,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderValueImpression: apacdex.Builder, openrtb_ext.BidderVerizonMedia: yahoossp.Builder, openrtb_ext.BidderVideoByte: videobyte.Builder, + openrtb_ext.BidderVideoHeroes: videoheroes.Builder, openrtb_ext.BidderVidoomy: vidoomy.Builder, openrtb_ext.BidderViewdeos: adtelligent.Builder, openrtb_ext.BidderVisx: visx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index c5de0576718..fe128f2eebd 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -236,6 +236,7 @@ const ( BidderValueImpression BidderName = "valueimpression" BidderVerizonMedia BidderName = "verizonmedia" BidderVideoByte BidderName = "videobyte" + BidderVideoHeroes BidderName = "videoheroes" BidderVidoomy BidderName = "vidoomy" BidderViewdeos BidderName = "viewdeos" BidderVisx BidderName = "visx" @@ -406,6 +407,7 @@ func CoreBidderNames() []BidderName { BidderValueImpression, BidderVerizonMedia, BidderVideoByte, + BidderVideoHeroes, BidderVidoomy, BidderViewdeos, BidderVisx, diff --git a/openrtb_ext/imp_videoheroes.go b/openrtb_ext/imp_videoheroes.go new file mode 100644 index 00000000000..818f58c9f43 --- /dev/null +++ b/openrtb_ext/imp_videoheroes.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpVideoHeroes struct { + PlacementID string `json:"placementId"` +} diff --git a/static/bidder-info/videoheroes.yaml b/static/bidder-info/videoheroes.yaml new file mode 100644 index 00000000000..ed90d70c1ca --- /dev/null +++ b/static/bidder-info/videoheroes.yaml @@ -0,0 +1,14 @@ +endpoint: "http://point.contextualadv.com/?t=3&partner={{.PublisherID}}" +maintainer: + email: "support@videoheroes.tv" +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/videoheroes.json b/static/bidder-params/videoheroes.json new file mode 100644 index 00000000000..d442e95374b --- /dev/null +++ b/static/bidder-params/videoheroes.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "VideoHeroes Adapter Params", + "description": "A schema which validates params accepted by the VideoHeroes adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "Unique Placement ID of publisher" + } + }, + "required": ["placementId"] +} \ No newline at end of file